Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
use rustc_session::Session;
use rustc_session::lint::{BuiltinLintDiag, LintId};
use rustc_session::lint::LintId;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};

use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
Expand Down Expand Up @@ -124,14 +124,7 @@ impl<'sess> AttributeParser<'sess, Early> {
target,
OmitDoc::Skip,
std::convert::identity,
|lint_id, span, kind| {
sess.psess.buffer_lint(
lint_id.lint,
span,
target_node_id,
BuiltinLintDiag::AttributeLint(kind),
)
},
|lint_id, span, kind| sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind),
)
}

Expand Down Expand Up @@ -230,12 +223,7 @@ impl<'sess> AttributeParser<'sess, Early> {
let mut parser =
Self { features, tools: None, parse_only: None, sess, stage: Early { emit_errors } };
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
sess.psess.buffer_lint(
lint_id.lint,
span,
target_node_id,
BuiltinLintDiag::AttributeLint(kind),
)
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_attr_parsing/src/validate_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use rustc_hir::AttrPath;
use rustc_hir::lints::AttributeLintKind;
use rustc_parse::parse_in;
use rustc_session::errors::report_lit_error;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::ParseSess;
use rustc_span::{Span, Symbol, sym};
Expand Down Expand Up @@ -208,11 +207,11 @@ fn emit_malformed_attribute(
ILL_FORMED_ATTRIBUTE_INPUT,
span,
ast::CRATE_NODE_ID,
BuiltinLintDiag::AttributeLint(AttributeLintKind::IllFormedAttributeInput {
AttributeLintKind::IllFormedAttributeInput {
suggestions: suggestions.clone(),
docs: template.docs,
help: None,
}),
},
);
} else {
suggestions.sort();
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Span>,
#[suggestion(
"use the named argument by name to avoid ambiguity",
style = "verbose",
code = "{name}",
applicability = "maybe-incorrect"
)]
pub suggestion: Option<Span>,

pub name: String,
pub named_arg_name: String,
}
47 changes: 36 additions & 11 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ use rustc_ast::{
};
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};
Expand Down Expand Up @@ -611,14 +611,39 @@ fn make_format_args(
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::<rustc_session::Session>()
.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)
})),
});
}
}
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_errors/src/decorate_diag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_error_messages::MultiSpan;
use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId};
use rustc_lint_defs::{AttributeLintKind, Lint, LintId};

use crate::{Diag, DiagCtxtHandle, Diagnostic, Level};

/// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its
/// We can't implement `Diagnostic` for `AttributeLintKind`, because decorating some of its
/// variants requires types we don't have yet. So, handle that case separately.
pub enum DecorateDiagCompat {
/// The third argument of the closure is a `Session`. However, due to the dependency tree,
Expand All @@ -22,7 +22,7 @@ pub enum DecorateDiagCompat {
+ 'static,
>,
),
Builtin(BuiltinLintDiag),
Builtin(AttributeLintKind),
}

impl std::fmt::Debug for DecorateDiagCompat {
Expand All @@ -38,9 +38,9 @@ impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for De
}
}

impl From<BuiltinLintDiag> for DecorateDiagCompat {
impl From<AttributeLintKind> for DecorateDiagCompat {
#[inline]
fn from(b: BuiltinLintDiag) -> Self {
fn from(b: AttributeLintKind) -> Self {
Self::Builtin(b)
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_lint/src/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use tracing::debug;

use crate::context::{EarlyContext, LintContext, LintStore};
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
use crate::{DecorateBuiltinLint, DiagAndSess};
use crate::{DecorateAttrLint, DiagAndSess};

pub(super) mod diagnostics;

Expand All @@ -42,10 +42,10 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
self.context.opt_span_lint(
lint_id.lint,
span,
DecorateBuiltinLint {
DecorateAttrLint {
sess: self.context.sess(),
tcx: self.tcx,
diagnostic: b,
diagnostic: &b,
},
);
}
Expand Down
101 changes: 1 addition & 100 deletions compiler/rustc_lint/src/early/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ use std::any::Any;
use std::borrow::Cow;

use rustc_data_structures::sync::DynSend;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
elided_lifetime_in_path_suggestion,
};
use rustc_errors::{Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level};
use rustc_hir::lints::{AttributeLintKind, FormatWarning};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;

use crate::lints;

Expand All @@ -28,101 +24,6 @@ impl<'a> Diagnostic<'a, ()> for DiagAndSess<'_> {
}
}

/// This is a diagnostic struct that will decorate a `BuiltinLintDiag`
/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
pub struct DecorateBuiltinLint<'sess, 'tcx> {
pub sess: &'sess Session,
pub tcx: Option<TyCtxt<'tcx>>,
pub diagnostic: BuiltinLintDiag,
}

impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
match self.diagnostic {
BuiltinLintDiag::ElidedLifetimesInPaths(
n,
path_span,
incl_angl_brckt,
insertion_span,
) => lints::ElidedLifetimesInPaths {
subdiag: elided_lifetime_in_path_suggestion(
self.sess.source_map(),
n,
path_span,
incl_angl_brckt,
insertion_span,
),
}
.into_diag(dcx, level),
BuiltinLintDiag::UnusedImports {
remove_whole_use,
num_to_remove,
remove_spans,
test_module_span,
span_snippets,
} => {
let sugg = if remove_whole_use {
lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
} else {
lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
};
let test_module_span =
test_module_span.map(|span| self.sess.source_map().guess_head_span(span));

lints::UnusedImports {
sugg,
test_module_span,
num_snippets: span_snippets.len(),
span_snippets: DiagArgValue::StrListSepByAnd(
span_snippets.into_iter().map(Cow::Owned).collect(),
),
}
.into_diag(dcx, level)
}
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)
}
}
}
}

/// This is a diagnostic struct that will decorate a `AttributeLintKind`
/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
pub struct DecorateAttrLint<'a, 'sess, 'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ use unused::*;
#[rustfmt::skip]
pub use builtin::{MissingDoc, SoftLints};
pub use context::{EarlyContext, LateContext, LintContext, LintStore};
pub use early::diagnostics::{DecorateAttrLint, DecorateBuiltinLint, DiagAndSess};
pub use early::diagnostics::{DecorateAttrLint, DiagAndSess};
pub use early::{EarlyCheckNode, check_ast_node};
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
pub use levels::LintLevelsBuilder;
Expand Down
Loading
Loading