diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 171c15eb4b9f..87f1ff960a82 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1141,3 +1141,22 @@ pub(crate) struct EiiMacroExpectedMaxOneArgument { pub span: Span, pub name: String, } + +#[derive(Diagnostic)] +#[diag("named argument `{$named_arg_name}` is not used by name")] +pub(crate) struct NamedArgumentUsedPositionally { + #[label("this named argument is referred to by position in formatting string")] + pub named_arg_sp: Span, + #[label("this formatting argument uses named argument `{$named_arg_name}` by position")] + pub position_label_sp: Option, + #[suggestion( + "use the named argument by name to avoid ambiguity", + style = "verbose", + code = "{name}", + applicability = "maybe-incorrect" + )] + pub suggestion: Option, + + pub name: String, + pub named_arg_name: String, +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index f47dae5eba00..7d01868645a0 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -10,12 +10,12 @@ }; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - Applicability, BufferedEarlyLint, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, - pluralize, + Applicability, BufferedEarlyLint, DecorateDiagCompat, Diag, Diagnostic, MultiSpan, PResult, + SingleLabelManySpans, listify, pluralize, }; use rustc_expand::base::*; +use rustc_lint_defs::LintId; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; -use rustc_lint_defs::{BuiltinLintDiag, LintId}; use rustc_parse::exp; use rustc_parse_format as parse; use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol}; @@ -611,14 +611,39 @@ enum ArgRef<'a> { span: Some(arg_name.span.into()), node_id: rustc_ast::CRATE_NODE_ID, lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY), - diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally { - position_sp_to_replace, - position_sp_for_msg, - named_arg_sp: arg_name.span, - named_arg_name: arg_name.name.to_string(), - is_formatting_arg: matches!(used_as, Width | Precision), - } - .into(), + diagnostic: DecorateDiagCompat::Dynamic(Box::new(move |dcx, level, sess| { + let (suggestion, name) = + if let Some(positional_arg_to_replace) = position_sp_to_replace { + let mut name = arg_name.name.to_string(); + let is_formatting_arg = matches!(used_as, Width | Precision); + if is_formatting_arg { + name.push('$') + }; + let span_to_replace = if let Ok(positional_arg_content) = sess + .downcast_ref::() + .expect("expected a `Session`") + .source_map() + .span_to_snippet(positional_arg_to_replace) + && positional_arg_content.starts_with(':') + { + positional_arg_to_replace.shrink_to_lo() + } else { + positional_arg_to_replace + }; + (Some(span_to_replace), name) + } else { + (None, String::new()) + }; + + errors::NamedArgumentUsedPositionally { + named_arg_sp: arg_name.span, + position_label_sp: position_sp_for_msg, + suggestion, + name, + named_arg_name: arg_name.name.to_string(), + } + .into_diag(dcx, level) + })), }); } } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 3566bd384f4a..fe1a0bf1394e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -36,42 +36,6 @@ pub struct DecorateBuiltinLint<'sess, 'tcx> { impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { match self.diagnostic { - BuiltinLintDiag::NamedArgumentUsedPositionally { - position_sp_to_replace, - position_sp_for_msg, - named_arg_sp, - named_arg_name, - is_formatting_arg, - } => { - let (suggestion, name) = - if let Some(positional_arg_to_replace) = position_sp_to_replace { - let mut name = named_arg_name.clone(); - if is_formatting_arg { - name.push('$') - }; - let span_to_replace = if let Ok(positional_arg_content) = - self.sess.source_map().span_to_snippet(positional_arg_to_replace) - && positional_arg_content.starts_with(':') - { - positional_arg_to_replace.shrink_to_lo() - } else { - positional_arg_to_replace - }; - (Some(span_to_replace), name) - } else { - (None, String::new()) - }; - - lints::NamedArgumentUsedPositionally { - named_arg_sp, - position_label_sp: position_sp_for_msg, - suggestion, - name, - named_arg_name, - } - .into_diag(dcx, level) - } - BuiltinLintDiag::AttributeLint(kind) => { DecorateAttrLint { sess: self.sess, tcx: self.tcx, diagnostic: &kind } .into_diag(dcx, level) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0a24d2d0cdb9..f52b90382d95 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3039,25 +3039,6 @@ pub(crate) struct IllFormedAttributeInputHelp { pub lint: String, } -#[derive(Diagnostic)] -#[diag("named argument `{$named_arg_name}` is not used by name")] -pub(crate) struct NamedArgumentUsedPositionally { - #[label("this named argument is referred to by position in formatting string")] - pub named_arg_sp: Span, - #[label("this formatting argument uses named argument `{$named_arg_name}` by position")] - pub position_label_sp: Option, - #[suggestion( - "use the named argument by name to avoid ambiguity", - style = "verbose", - code = "{name}", - applicability = "maybe-incorrect" - )] - pub suggestion: Option, - - pub name: String, - pub named_arg_name: String, -} - #[derive(Diagnostic)] #[diag("creating a {$shared_label}reference to mutable static")] pub(crate) struct RefOfMutStatic<'a> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index d235e66c20d8..b24adda06f98 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -656,19 +656,6 @@ pub enum DeprecatedSinceKind { // becomes hacky (and it gets allocated). #[derive(Debug)] pub enum BuiltinLintDiag { - NamedArgumentUsedPositionally { - /// Span where the named argument is used by position and will be replaced with the named - /// argument name - position_sp_to_replace: Option, - /// Span where the named argument is used by position and is used for lint messages - position_sp_for_msg: Option, - /// Span where the named argument's name is (so we know where to put the warning message) - named_arg_sp: Span, - /// String containing the named arguments name - named_arg_name: String, - /// Indicates if the named argument is used as a width/precision for formatting - is_formatting_arg: bool, - }, AttributeLint(AttributeLintKind), }