From b6eb2659025a94c3eced1fdf27b5482476cc3d15 Mon Sep 17 00:00:00 2001 From: Haoran Wang Date: Sat, 23 May 2026 08:42:56 +0800 Subject: [PATCH] Keep redundant-capture suggestions syntactically valid The lint suggestion now removes the `+` joiner adjacent to a redundant `use<...>` clause, so applying the suggestion does not leave a dangling `+` that fails to parse. The existing `tests/ui/impl-trait/precise-capturing/redundant.stderr` baseline emits the same diagnostic with the expanded suggestion span and is blessed along with the new `run-rustfix` test. Tested: - ./x test tests/ui/impl-trait/precise-capturing/redundant.rs --force-rerun - ./x test tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.rs --force-rerun - ./x test tidy --- .../rustc_lint/src/impl_trait_overcaptures.rs | 22 ++++++++++--- .../redundant-machine-applicable.fixed | 28 ++++++++++++++++ .../redundant-machine-applicable.rs | 28 ++++++++++++++++ .../redundant-machine-applicable.stderr | 32 +++++++++++++++++++ .../precise-capturing/redundant.stderr | 24 +++++++------- 5 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.fixed create mode 100644 tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.rs create mode 100644 tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.stderr diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 65dfa8b93de7..76d55030b131 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -361,9 +361,9 @@ fn visit_ty(&mut self, t: Ty<'tcx>) { // have no uncaptured args, then we should warn to the user that // it's redundant to capture all args explicitly. if new_capture_rules - && let Some((captured_args, capturing_span)) = - opaque.bounds.iter().find_map(|bound| match *bound { - hir::GenericBound::Use(a, s) => Some((a, s)), + && let Some((use_idx, captured_args, capturing_span)) = + opaque.bounds.iter().enumerate().find_map(|(i, bound)| match *bound { + hir::GenericBound::Use(a, s) => Some((i, a, s)), _ => None, }) { @@ -400,11 +400,25 @@ fn visit_ty(&mut self, t: Ty<'tcx>) { .iter() .all(|(def_id, _)| explicitly_captured.contains(def_id)) { + // Extend the removal span to include the `+` joiner adjacent + // to `use<...>`, so applying the suggestion does not leave + // behind a stray `+` that fails to parse. + let suggestion_span = if let Some(next) = opaque.bounds.get(use_idx + 1) { + capturing_span.with_hi(next.span().lo()) + } else if let Some(prev_idx) = use_idx.checked_sub(1) { + let prev = opaque.bounds[prev_idx]; + capturing_span.with_lo(prev.span().hi()) + } else { + // `impl use<...>` with no other bound is not valid + // syntax, so this branch is unreachable in practice. + capturing_span + }; + self.tcx.emit_node_span_lint( IMPL_TRAIT_REDUNDANT_CAPTURES, self.tcx.local_def_id_to_hir_id(opaque_def_id), opaque_span, - ImplTraitRedundantCapturesLint { capturing_span }, + ImplTraitRedundantCapturesLint { capturing_span: suggestion_span }, ); } } diff --git a/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.fixed b/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.fixed new file mode 100644 index 000000000000..d8a7858e7659 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.fixed @@ -0,0 +1,28 @@ +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ edition: 2024 + +// Verify that the suggestion produced by `impl_trait_redundant_captures` +// removes the adjacent `+` joiner along with `use<...>`, instead of leaving +// behind a stray `+` that fails to compile. Regression test for +// https://github.com/rust-lang/rust/issues/143216. + +#![allow(unused)] +#![deny(impl_trait_redundant_captures)] + +// `use<>` at the end of the bound list: the suggestion must remove the +// preceding `+`. +fn end_position() -> impl Sized {} +//~^ ERROR all possible in-scope parameters are already captured + +// `use<>` at the start of the bound list: the suggestion must remove the +// following `+`. +fn start_position() -> impl Sized {} +//~^ ERROR all possible in-scope parameters are already captured + +// `use<>` in the middle of the bound list: the suggestion must remove +// exactly one `+`, keeping the other to join the remaining bounds. +fn middle_position() -> impl Sized + Send {} +//~^ ERROR all possible in-scope parameters are already captured + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.rs b/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.rs new file mode 100644 index 000000000000..c6b2d4cba1c2 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.rs @@ -0,0 +1,28 @@ +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ edition: 2024 + +// Verify that the suggestion produced by `impl_trait_redundant_captures` +// removes the adjacent `+` joiner along with `use<...>`, instead of leaving +// behind a stray `+` that fails to compile. Regression test for +// https://github.com/rust-lang/rust/issues/143216. + +#![allow(unused)] +#![deny(impl_trait_redundant_captures)] + +// `use<>` at the end of the bound list: the suggestion must remove the +// preceding `+`. +fn end_position() -> impl Sized + use<> {} +//~^ ERROR all possible in-scope parameters are already captured + +// `use<>` at the start of the bound list: the suggestion must remove the +// following `+`. +fn start_position() -> impl use<> + Sized {} +//~^ ERROR all possible in-scope parameters are already captured + +// `use<>` in the middle of the bound list: the suggestion must remove +// exactly one `+`, keeping the other to join the remaining bounds. +fn middle_position() -> impl Sized + use<> + Send {} +//~^ ERROR all possible in-scope parameters are already captured + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.stderr b/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.stderr new file mode 100644 index 000000000000..f07fc4905680 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant-machine-applicable.stderr @@ -0,0 +1,32 @@ +error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant-machine-applicable.rs:15:22 + | +LL | fn end_position() -> impl Sized + use<> {} + | ^^^^^^^^^^-------- + | | + | help: remove the `use<...>` syntax + | +note: the lint level is defined here + --> $DIR/redundant-machine-applicable.rs:11:9 + | +LL | #![deny(impl_trait_redundant_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant-machine-applicable.rs:20:24 + | +LL | fn start_position() -> impl use<> + Sized {} + | ^^^^^--------^^^^^ + | | + | help: remove the `use<...>` syntax + +error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant-machine-applicable.rs:25:25 + | +LL | fn middle_position() -> impl Sized + use<> + Send {} + | ^^^^^^^^^^^^^--------^^^^ + | | + | help: remove the `use<...>` syntax + +error: aborting due to 3 previous errors + diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr index c9f84d360e3c..62724fc01976 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.stderr +++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr @@ -2,9 +2,9 @@ error: all possible in-scope parameters are already captured, so `use<...>` synt --> $DIR/redundant.rs:5:19 | LL | fn hello<'a>() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax + | ^^^^^^^^^^---------- + | | + | help: remove the `use<...>` syntax | note: the lint level is defined here --> $DIR/redundant.rs:3:9 @@ -16,25 +16,25 @@ error: all possible in-scope parameters are already captured, so `use<...>` synt --> $DIR/redundant.rs:10:27 | LL | fn inherent(&self) -> impl Sized + use<'_> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax + | ^^^^^^^^^^---------- + | | + | help: remove the `use<...>` syntax error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant --> $DIR/redundant.rs:15:22 | LL | fn in_trait() -> impl Sized + use<'a, Self>; - | ^^^^^^^^^^^^^------------- - | | - | help: remove the `use<...>` syntax + | ^^^^^^^^^^---------------- + | | + | help: remove the `use<...>` syntax error: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant --> $DIR/redundant.rs:19:22 | LL | fn in_trait() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax + | ^^^^^^^^^^---------- + | | + | help: remove the `use<...>` syntax error: aborting due to 4 previous errors