about summary refs log tree commit diff
diff options
context:
space:
mode:
authoryukang <moorekang@gmail.com>2023-10-30 19:20:56 +0800
committeryukang <moorekang@gmail.com>2023-10-30 21:35:18 +0800
commit82f34fdd2313b27a4f3e28bed74163154e231b9e (patch)
tree5d67508b283566a330e56ffa7ac95b5ed27ace83
parent91bbdd927a5e53a2fe126304fe8adbedf339616c (diff)
downloadrust-82f34fdd2313b27a4f3e28bed74163154e231b9e.tar.gz
rust-82f34fdd2313b27a4f3e28bed74163154e231b9e.zip
Fix #117284, Fix unused variables lint issue for args in macro
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/errors.rs21
-rw-r--r--compiler/rustc_passes/src/liveness.rs25
-rw-r--r--tests/ui/lint/unused/issue-117284-arg-in-macro.rs17
-rw-r--r--tests/ui/lint/unused/issue-117284-arg-in-macro.stderr29
5 files changed, 84 insertions, 11 deletions
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 026186cbe6c..a0a98dd8536 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 eca0fb7748b..bc31b5db021 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<UnusedVariableStringInterp>,
     #[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<Span>,
-    pub name: String,
+pub enum UnusedVariableSugg {
+    #[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+    TryPrefixSugg {
+        #[suggestion_part(code = "_{name}")]
+        spans: Vec<Span>,
+        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 d068fe62473..b73fb984c0e 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::<Vec<_>>();
+
                     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::<Vec<_>>(),
                         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 00000000000..eea0f4c594d
--- /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 00000000000..84efaa4f368
--- /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
+