From 82f34fdd2313b27a4f3e28bed74163154e231b9e Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 30 Oct 2023 19:20:56 +0800 Subject: [PATCH] Fix #117284, Fix unused variables lint issue for args in macro --- compiler/rustc_passes/messages.ftl | 3 ++ compiler/rustc_passes/src/errors.rs | 21 ++++++++++---- compiler/rustc_passes/src/liveness.rs | 25 ++++++++++++---- .../lint/unused/issue-117284-arg-in-macro.rs | 17 +++++++++++ .../unused/issue-117284-arg-in-macro.stderr | 29 +++++++++++++++++++ 5 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 tests/ui/lint/unused/issue-117284-arg-in-macro.rs create mode 100644 tests/ui/lint/unused/issue-117284-arg-in-macro.stderr diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 026186cbe6cd3..a0a98dd853666 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -778,6 +778,8 @@ passes_unused_var_maybe_capture_ref = unused variable: `{$name}` passes_unused_var_remove_field = unused variable: `{$name}` passes_unused_var_remove_field_suggestion = try removing the field +passes_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable + passes_unused_variable_try_ignore = unused variable: `{$name}` .suggestion = try ignoring the field @@ -785,6 +787,7 @@ passes_unused_variable_try_prefix = unused variable: `{$name}` .label = unused variable .suggestion = if this is intentional, prefix it with an underscore + passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index eca0fb7748b15..bc31b5db021d0 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1768,15 +1768,24 @@ pub struct UnusedVariableTryPrefix { #[subdiagnostic] pub string_interp: Vec, #[subdiagnostic] - pub sugg: UnusedVariableTryPrefixSugg, + pub sugg: UnusedVariableSugg, + pub name: String, } #[derive(Subdiagnostic)] -#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] -pub struct UnusedVariableTryPrefixSugg { - #[suggestion_part(code = "_{name}")] - pub spans: Vec, - pub name: String, +pub enum UnusedVariableSugg { + #[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")] + TryPrefixSugg { + #[suggestion_part(code = "_{name}")] + spans: Vec, + name: String, + }, + #[help(passes_unused_variable_args_in_macro)] + NoSugg { + #[primary_span] + span: Span, + name: String, + }, } pub struct UnusedVariableStringInterp { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index d068fe62473cd..b73fb984c0eac 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1580,7 +1580,6 @@ impl<'tcx> Liveness<'_, 'tcx> { opt_body: Option<&hir::Body<'_>>, ) { let first_hir_id = hir_ids_and_spans[0].0; - if let Some(name) = self.should_warn(var).filter(|name| name != "self") { // annoying: for parameters in funcs like `fn(x: i32) // {ret}`, there is only one node, so asking about @@ -1652,11 +1651,29 @@ impl<'tcx> Liveness<'_, 'tcx> { }, ); } else { + // #117284, when `pat_span` and `ident_span` have different contexts + // we can't provide a good suggestion, instead we pointed out the spans from macro + let from_macro = non_shorthands + .iter() + .find(|(_, pat_span, ident_span)| { + pat_span.ctxt() != ident_span.ctxt() && pat_span.from_expansion() + }) + .map(|(_, pat_span, _)| *pat_span); let non_shorthands = non_shorthands .into_iter() .map(|(_, _, ident_span)| ident_span) .collect::>(); + let suggestions = self.string_interp_suggestions(&name, opt_body); + let sugg = if let Some(span) = from_macro { + errors::UnusedVariableSugg::NoSugg { span, name: name.clone() } + } else { + errors::UnusedVariableSugg::TryPrefixSugg { + spans: non_shorthands, + name: name.clone(), + } + }; + self.ir.tcx.emit_spanned_lint( lint::builtin::UNUSED_VARIABLES, first_hir_id, @@ -1666,10 +1683,8 @@ impl<'tcx> Liveness<'_, 'tcx> { .collect::>(), errors::UnusedVariableTryPrefix { label: if !suggestions.is_empty() { Some(pat.span) } else { None }, - sugg: errors::UnusedVariableTryPrefixSugg { - spans: non_shorthands, - name, - }, + name, + sugg, string_interp: suggestions, }, ); diff --git a/tests/ui/lint/unused/issue-117284-arg-in-macro.rs b/tests/ui/lint/unused/issue-117284-arg-in-macro.rs new file mode 100644 index 0000000000000..eea0f4c594dc8 --- /dev/null +++ b/tests/ui/lint/unused/issue-117284-arg-in-macro.rs @@ -0,0 +1,17 @@ +#![deny(unused_variables)] +macro_rules! make_var { + ($struct:ident, $var:ident) => { + let $var = $struct.$var; + }; +} + +#[allow(unused)] +struct MyStruct { + var: i32, +} + +fn main() { + let s = MyStruct { var: 42 }; + make_var!(s, var); //~ ERROR unused variable: `var` + let a = 1; //~ ERROR unused variable: `a` +} diff --git a/tests/ui/lint/unused/issue-117284-arg-in-macro.stderr b/tests/ui/lint/unused/issue-117284-arg-in-macro.stderr new file mode 100644 index 0000000000000..84efaa4f3687b --- /dev/null +++ b/tests/ui/lint/unused/issue-117284-arg-in-macro.stderr @@ -0,0 +1,29 @@ +error: unused variable: `var` + --> $DIR/issue-117284-arg-in-macro.rs:15:18 + | +LL | make_var!(s, var); + | ^^^ + | +help: `var` is captured in macro and introduced a unused variable + --> $DIR/issue-117284-arg-in-macro.rs:4:13 + | +LL | let $var = $struct.$var; + | ^^^^ +... +LL | make_var!(s, var); + | ----------------- in this macro invocation +note: the lint level is defined here + --> $DIR/issue-117284-arg-in-macro.rs:1:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `make_var` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unused variable: `a` + --> $DIR/issue-117284-arg-in-macro.rs:16:9 + | +LL | let a = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: aborting due to 2 previous errors +