diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bf6d3322176..8718bba1fd6 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -16,7 +16,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; -use rustc_session::lint::LintBuffer; +use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -213,14 +213,14 @@ impl<'a> AstValidator<'a> { err.emit(); } - fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) { + fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { for Param { pat, .. } in &decl.inputs { match pat.kind { PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {} - PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => { - report_err(pat.span, true) + PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => { + report_err(pat.span, Some(ident), true) } - _ => report_err(pat.span, false), + _ => report_err(pat.span, None, false), } } } @@ -815,7 +815,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match ty.kind { TyKind::BareFn(ref bfty) => { self.check_fn_decl(&bfty.decl, SelfSemantic::No); - Self::check_decl_no_pat(&bfty.decl, |span, _| { + Self::check_decl_no_pat(&bfty.decl, |span, _, _| { struct_span_err!( self.session, span, @@ -1285,7 +1285,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Functions without bodies cannot have patterns. if let FnKind::Fn(ctxt, _, sig, _, None) = fk { - Self::check_decl_no_pat(&sig.decl, |span, mut_ident| { + Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { let (code, msg, label) = match ctxt { FnCtxt::Foreign => ( error_code!(E0130), @@ -1299,7 +1299,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ), }; if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { - self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg); + if let Some(ident) = ident { + let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident); + self.lint_buffer.buffer_lint_with_diagnostic( + PATTERNS_IN_FNS_WITHOUT_BODY, + id, + span, + msg, + diag, + ) + } } else { self.err_handler() .struct_span_err(span, msg) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index bfeef490489..d0e46426ff5 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -596,6 +596,9 @@ pub trait LintContext: Sized { db.help("to document an item produced by a macro, \ the macro must produce the documentation as part of its expansion"); } + BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident) => { + db.span_suggestion(span, "remove `mut` from the parameter", ident.to_string(), Applicability::MachineApplicable); + } } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index aec0fc253ca..2bfc6a85576 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -253,6 +253,7 @@ pub enum BuiltinLintDiagnostics { RedundantImport(Vec<(Span, bool)>, Ident), DeprecatedMacro(Option, Span), UnusedDocComment(Span), + PatternsInFnsWithoutBody(Span, Ident), } /// Lints that are buffered up early on in the `Session` before the