Auto merge of #155760 - GuillaumeGomez:rm-attributelintkind, r=JonathanBrouwer,petrochenkov

Remove `AttributeLintKind`



Part of https://github.com/rust-lang/rust/issues/153099.

The `AttributeLintKind` type is finally gone! \o/

Diff is this big because I moved a file and a lot of `Diagnostic` types. :')

r? @JonathanBrouwer
This commit is contained in:
bors
2026-04-27 17:49:21 +00:00
22 changed files with 568 additions and 662 deletions
+14 -19
View File
@@ -41,7 +41,7 @@
use rustc_ast::node_id::NodeMap;
use rustc_ast::visit::Visitor;
use rustc_ast::{self as ast, *};
use rustc_attr_parsing::{AttributeParser, EmitAttribute, Late, OmitDoc};
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::sorted_map::SortedMap;
@@ -52,7 +52,7 @@
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::PerParentDisambiguatorState;
use rustc_hir::lints::{AttributeLint, DelayedLint, DynAttribute};
use rustc_hir::lints::DelayedLint;
use rustc_hir::{
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
@@ -1096,23 +1096,18 @@ fn lower_attrs_vec(
target,
OmitDoc::Lower,
|s| l.lower(s),
|lint_id, span, kind| match kind {
EmitAttribute::Static(attr_kind) => {
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
lint_id,
id: target_hir_id,
span,
kind: attr_kind,
}));
}
EmitAttribute::Dynamic(callback) => {
self.delayed_lints.push(DelayedLint::Dynamic(DynAttribute {
lint_id,
id: target_hir_id,
span,
callback,
}));
}
|lint_id, span, kind| {
self.delayed_lints.push(DelayedLint {
lint_id,
id: target_hir_id,
span,
callback: Box::new(move |dcx, level, sess: &dyn std::any::Any| {
let sess = sess
.downcast_ref::<rustc_session::Session>()
.expect("expected `Session`");
(kind.0)(dcx, level, sess)
}),
});
},
)
}
@@ -3,12 +3,11 @@
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{AttrItem, Attribute, LitKind, ast, token};
use rustc_errors::{Applicability, PResult, msg};
use rustc_errors::{Applicability, Diagnostic, PResult, msg};
use rustc_feature::{
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, RustcVersion, Target};
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
use rustc_parse::{exp, parse_in};
@@ -20,6 +19,7 @@
use thin_vec::ThinVec;
use crate::attributes::AttributeSafety;
use crate::attributes::diagnostic::check_cfg;
use crate::context::{AcceptContext, ShouldEmit, Stage};
use crate::parser::{
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
@@ -224,14 +224,19 @@ pub(crate) fn parse_name_value<S: Stage>(
match cx.sess.psess.check_config.expecteds.get(&name) {
Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx
.emit_lint(
.emit_dyn_lint_with_sess(
UNEXPECTED_CFGS,
AttributeLintKind::UnexpectedCfgValue((name, name_span), value),
move |dcx, level, sess| {
check_cfg::unexpected_cfg_value(sess, (name, name_span), value)
.into_diag(dcx, level)
},
span,
),
None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint(
None if cx.sess.psess.check_config.exhaustive_names => cx.emit_dyn_lint_with_sess(
UNEXPECTED_CFGS,
AttributeLintKind::UnexpectedCfgName((name, name_span), value),
move |dcx, level, sess| {
check_cfg::unexpected_cfg_name(sess, (name, name_span), value).into_diag(dcx, level)
},
span,
),
_ => { /* not unexpected */ }
@@ -1,12 +1,10 @@
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::config::ExpectedValues;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::{ExpnKind, Ident, Span, Symbol, sym};
use crate::lints;
use crate::errors;
const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
@@ -64,57 +62,48 @@ fn to_check_cfg_arg(name: Ident, value: Option<Symbol>, quotes: EscapeQuotes) ->
fn cargo_help_sub(
sess: &Session,
inst: &impl Fn(EscapeQuotes) -> String,
) -> lints::UnexpectedCfgCargoHelp {
) -> errors::UnexpectedCfgCargoHelp {
// We don't want to suggest the `build.rs` way to expected cfgs if we are already in a
// `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is
// `build_script_build`) to try to figure out if we are building a Cargo build script
let unescaped = &inst(EscapeQuotes::No);
if let Some("build_script_build") = sess.opts.crate_name.as_deref() {
lints::UnexpectedCfgCargoHelp::lint_cfg(unescaped)
errors::UnexpectedCfgCargoHelp::lint_cfg(unescaped)
} else {
lints::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes))
errors::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes))
}
}
fn rustc_macro_help(span: Span) -> Option<lints::UnexpectedCfgRustcMacroHelp> {
fn rustc_macro_help(span: Span) -> Option<errors::UnexpectedCfgRustcMacroHelp> {
let oexpn = span.ctxt().outer_expn_data();
if let Some(def_id) = oexpn.macro_def_id
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
&& def_id.krate != LOCAL_CRATE
{
Some(lints::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name })
Some(errors::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name })
} else {
None
}
}
fn cargo_macro_help(
tcx: Option<TyCtxt<'_>>,
span: Span,
) -> Option<lints::UnexpectedCfgCargoMacroHelp> {
fn cargo_macro_help(span: Span) -> Option<errors::UnexpectedCfgCargoMacroHelp> {
let oexpn = span.ctxt().outer_expn_data();
if let Some(def_id) = oexpn.macro_def_id
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
&& def_id.krate != LOCAL_CRATE
&& let Some(tcx) = tcx
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
{
Some(lints::UnexpectedCfgCargoMacroHelp {
macro_kind: macro_kind.descr(),
macro_name,
crate_name: tcx.crate_name(def_id.krate),
})
Some(errors::UnexpectedCfgCargoMacroHelp { macro_kind: macro_kind.descr(), macro_name })
} else {
None
}
}
pub(super) fn unexpected_cfg_name(
pub(crate) fn unexpected_cfg_name(
sess: &Session,
tcx: Option<TyCtxt<'_>>,
(name, name_span): (Symbol, Span),
value: Option<(Symbol, Span)>,
) -> lints::UnexpectedCfgName {
) -> errors::UnexpectedCfgName {
#[allow(rustc::potential_query_instability)]
let possibilities: Vec<Symbol> = sess.psess.check_config.expecteds.keys().copied().collect();
@@ -149,12 +138,12 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
}
let code_sugg = if is_feature_cfg && is_from_cargo {
lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures
errors::unexpected_cfg_name::CodeSuggestion::DefineFeatures
// Suggest correct `version("..")` predicate syntax
} else if let Some((_value, value_span)) = value
&& name == sym::version
{
lints::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
errors::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
between_name_and_value: name_span.between(value_span),
after_value: value_span.shrink_to_hi(),
}
@@ -169,7 +158,7 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
.span_to_snippet(name_span)
.map_or(true, |snippet| !snippet.contains("r#"))
{
lints::unexpected_cfg_name::CodeSuggestion::BooleanLiteral {
errors::unexpected_cfg_name::CodeSuggestion::BooleanLiteral {
span: name_span,
literal: boolean,
}
@@ -189,7 +178,7 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
if !possibilities.is_empty() {
let possibilities =
possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
Some(errors::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
} else {
None
}
@@ -198,37 +187,37 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
let best_match = Ident::new(best_match, name_span);
if let Some((value, value_span)) = value {
if best_match_values.contains(&Some(value)) {
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
span: name_span,
code: best_match.to_string(),
}
} else if best_match_values.contains(&None) {
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
span: name_span.to(value_span),
code: best_match.to_string(),
}
} else if let Some(first_value) = possibilities.first() {
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
span: name_span.to(value_span),
code: format!("{best_match} = \"{first_value}\""),
expected: get_possibilities_sub(),
}
} else {
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
span: name_span.to(value_span),
code: best_match.to_string(),
expected: get_possibilities_sub(),
}
}
} else {
lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
span: name_span,
code: best_match.to_string(),
expected: get_possibilities_sub(),
}
}
} else {
lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
span: name_span,
code: best_match.to_string(),
expected: None,
@@ -239,7 +228,7 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
names_possibilities.sort();
names_possibilities
.iter()
.map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue {
.map(|cfg_name| errors::unexpected_cfg_name::FoundWithSimilarValue {
span: name_span,
code: format!("{cfg_name} = \"{name}\""),
})
@@ -253,14 +242,14 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
let expected_names = if !possibilities.is_empty() {
let possibilities: Vec<_> =
possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect();
Some(lints::unexpected_cfg_name::ExpectedNames {
Some(errors::unexpected_cfg_name::ExpectedNames {
possibilities: possibilities.into(),
and_more,
})
} else {
None
};
lints::unexpected_cfg_name::CodeSuggestion::SimilarValues {
errors::unexpected_cfg_name::CodeSuggestion::SimilarValues {
with_similar_values: similar_values,
expected_names,
}
@@ -276,29 +265,28 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
} else {
None
};
lints::unexpected_cfg_name::InvocationHelp::Cargo {
errors::unexpected_cfg_name::InvocationHelp::Cargo {
help,
macro_help: cargo_macro_help(tcx, name_span),
macro_help: cargo_macro_help(name_span),
}
} else {
let help = lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No));
lints::unexpected_cfg_name::InvocationHelp::Rustc {
let help = errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No));
errors::unexpected_cfg_name::InvocationHelp::Rustc {
help,
macro_help: rustc_macro_help(name_span),
}
};
lints::UnexpectedCfgName { code_sugg, invocation_help, name }
errors::UnexpectedCfgName { code_sugg, invocation_help, name }
}
pub(super) fn unexpected_cfg_value(
pub(crate) fn unexpected_cfg_value(
sess: &Session,
tcx: Option<TyCtxt<'_>>,
(name, name_span): (Symbol, Span),
value: Option<(Symbol, Span)>,
) -> lints::UnexpectedCfgValue {
) -> errors::UnexpectedCfgValue {
let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else {
bug!(
panic!(
"it shouldn't be possible to have a diagnostic on a value whose name is not in values"
);
};
@@ -327,13 +315,13 @@ pub(super) fn unexpected_cfg_value(
.iter()
.take(max_suggestions)
.copied()
.map(|name| lints::unexpected_cfg_value::ChangeNameSuggestion {
.map(|name| errors::unexpected_cfg_value::ChangeNameSuggestion {
span: name_span,
name,
value,
})
.collect::<Vec<_>>();
lints::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions }
errors::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions }
} else if !possibilities.is_empty() {
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
@@ -343,7 +331,7 @@ pub(super) fn unexpected_cfg_value(
possibilities.clone(),
FilterWellKnownNames::No,
);
lints::unexpected_cfg_value::ExpectedValues {
errors::unexpected_cfg_value::ExpectedValues {
name,
have_none_possibility,
possibilities: possibilities.into(),
@@ -354,7 +342,7 @@ pub(super) fn unexpected_cfg_value(
let suggestion = if let Some((value, value_span)) = value {
// Suggest the most probable if we found one
if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
span: value_span,
best_match,
})
@@ -362,7 +350,7 @@ pub(super) fn unexpected_cfg_value(
None
}
} else if let &[first_possibility] = &possibilities[..] {
Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
span: name_span.shrink_to_hi(),
first_possibility,
})
@@ -370,21 +358,21 @@ pub(super) fn unexpected_cfg_value(
None
};
lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
errors::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
} else if have_none_possibility {
let suggestion =
value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion {
value.map(|(_value, value_span)| errors::unexpected_cfg_value::RemoveValueSuggestion {
span: name_span.shrink_to_hi().to(value_span),
});
lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
errors::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
} else {
let span = if let Some((_value, value_span)) = value {
name_span.to(value_span)
} else {
name_span
};
let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span };
lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
let suggestion = errors::unexpected_cfg_value::RemoveConditionSuggestion { span };
errors::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
};
// We don't want to encourage people to add values to a well-known names, as these are
@@ -405,32 +393,32 @@ pub(super) fn unexpected_cfg_value(
let invocation_help = if is_from_cargo {
let help = if name == sym::feature && !is_from_external_macro {
if let Some((value, _value_span)) = value {
Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value })
Some(errors::unexpected_cfg_value::CargoHelp::AddFeature { value })
} else {
Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
Some(errors::unexpected_cfg_value::CargoHelp::DefineFeatures)
}
} else if can_suggest_adding_value && !is_from_external_macro {
Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
Some(errors::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
} else {
None
};
lints::unexpected_cfg_value::InvocationHelp::Cargo {
errors::unexpected_cfg_value::InvocationHelp::Cargo {
help,
macro_help: cargo_macro_help(tcx, name_span),
macro_help: cargo_macro_help(name_span),
}
} else {
let help = if can_suggest_adding_value {
Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
Some(errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
} else {
None
};
lints::unexpected_cfg_value::InvocationHelp::Rustc {
errors::unexpected_cfg_value::InvocationHelp::Rustc {
help,
macro_help: rustc_macro_help(name_span),
}
};
lints::UnexpectedCfgValue {
errors::UnexpectedCfgValue {
code_sugg,
invocation_help,
has_value: value.is_some(),
@@ -23,6 +23,7 @@
};
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
pub(crate) mod check_cfg;
pub(crate) mod do_not_recommend;
pub(crate) mod on_const;
pub(crate) mod on_move;
+19 -14
View File
@@ -11,7 +11,6 @@
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, HirId};
use rustc_parse::parser::Recovery;
use rustc_session::Session;
@@ -460,18 +459,6 @@ pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuarant
self.stage.emit_err(&self.sess, diag)
}
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
pub(crate) fn emit_lint(
&mut self,
lint: &'static Lint,
kind: AttributeLintKind,
span: impl Into<MultiSpan>,
) {
self.emit_lint_inner(lint, EmitAttribute::Static(kind), span);
}
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
@@ -483,7 +470,25 @@ pub(crate) fn emit_dyn_lint<
callback: F,
span: impl Into<MultiSpan>,
) {
self.emit_lint_inner(lint, EmitAttribute::Dynamic(Box::new(callback)), span);
self.emit_lint_inner(
lint,
EmitAttribute(Box::new(move |dcx, level, _| callback(dcx, level))),
span,
);
}
pub(crate) fn emit_dyn_lint_with_sess<
F: for<'a> Fn(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()>
+ DynSend
+ DynSync
+ 'static,
>(
&mut self,
lint: &'static Lint,
callback: F,
span: impl Into<MultiSpan>,
) {
self.emit_lint_inner(lint, EmitAttribute(Box::new(callback)), span);
}
fn emit_lint_inner(
+368
View File
@@ -421,3 +421,371 @@ pub(crate) enum FormatWarning {
allowed: &'static str,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum UnexpectedCfgCargoHelp {
#[help("consider using a Cargo feature instead")]
#[help(
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
)]
LintCfg { cargo_toml_lint_cfg: String },
#[help("consider using a Cargo feature instead")]
#[help(
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
)]
#[help("or consider adding `{$build_rs_println}` to the top of the `build.rs`")]
LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String },
}
impl UnexpectedCfgCargoHelp {
fn cargo_toml_lint_cfg(unescaped: &str) -> String {
format!(
"\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}"
)
}
pub(crate) fn lint_cfg(unescaped: &str) -> Self {
UnexpectedCfgCargoHelp::LintCfg {
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
}
}
pub(crate) fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self {
UnexpectedCfgCargoHelp::LintCfgAndBuildRs {
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"),
}
}
}
#[derive(Subdiagnostic)]
#[help("to expect this configuration use `{$cmdline_arg}`")]
pub(crate) struct UnexpectedCfgRustcHelp {
pub cmdline_arg: String,
}
impl UnexpectedCfgRustcHelp {
pub(crate) fn new(unescaped: &str) -> Self {
Self { cmdline_arg: format!("--check-cfg={unescaped}") }
}
}
#[derive(Subdiagnostic)]
#[note(
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
)]
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
pub(crate) struct UnexpectedCfgRustcMacroHelp {
pub macro_kind: &'static str,
pub macro_name: Symbol,
}
#[derive(Subdiagnostic)]
#[note(
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
)]
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
pub(crate) struct UnexpectedCfgCargoMacroHelp {
pub macro_kind: &'static str,
pub macro_name: Symbol,
}
#[derive(Diagnostic)]
#[diag("unexpected `cfg` condition name: `{$name}`")]
pub(crate) struct UnexpectedCfgName {
#[subdiagnostic]
pub code_sugg: unexpected_cfg_name::CodeSuggestion,
#[subdiagnostic]
pub invocation_help: unexpected_cfg_name::InvocationHelp,
pub name: Symbol,
}
pub(crate) mod unexpected_cfg_name {
use rustc_errors::DiagSymbolList;
use rustc_macros::Subdiagnostic;
use rustc_span::{Ident, Span, Symbol};
#[derive(Subdiagnostic)]
pub(crate) enum CodeSuggestion {
#[help("consider defining some features in `Cargo.toml`")]
DefineFeatures,
#[multipart_suggestion(
"there is a similar config predicate: `version(\"..\")`",
applicability = "machine-applicable"
)]
VersionSyntax {
#[suggestion_part(code = "(")]
between_name_and_value: Span,
#[suggestion_part(code = ")")]
after_value: Span,
},
#[suggestion(
"there is a config with a similar name and value",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarNameAndValue {
#[primary_span]
span: Span,
code: String,
},
#[suggestion(
"there is a config with a similar name and no value",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarNameNoValue {
#[primary_span]
span: Span,
code: String,
},
#[suggestion(
"there is a config with a similar name and different values",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarNameDifferentValues {
#[primary_span]
span: Span,
code: String,
#[subdiagnostic]
expected: Option<ExpectedValues>,
},
#[suggestion(
"there is a config with a similar name",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarName {
#[primary_span]
span: Span,
code: String,
#[subdiagnostic]
expected: Option<ExpectedValues>,
},
SimilarValues {
#[subdiagnostic]
with_similar_values: Vec<FoundWithSimilarValue>,
#[subdiagnostic]
expected_names: Option<ExpectedNames>,
},
#[suggestion(
"you may have meant to use `{$literal}` (notice the capitalization). Doing so makes this predicate evaluate to `{$literal}` unconditionally",
applicability = "machine-applicable",
style = "verbose",
code = "{literal}"
)]
BooleanLiteral {
#[primary_span]
span: Span,
literal: bool,
},
}
#[derive(Subdiagnostic)]
#[help("expected values for `{$best_match}` are: {$possibilities}")]
pub(crate) struct ExpectedValues {
pub best_match: Symbol,
pub possibilities: DiagSymbolList,
}
#[derive(Subdiagnostic)]
#[suggestion(
"found config with similar value",
applicability = "maybe-incorrect",
code = "{code}"
)]
pub(crate) struct FoundWithSimilarValue {
#[primary_span]
pub span: Span,
pub code: String,
}
#[derive(Subdiagnostic)]
#[help_once(
"expected names are: {$possibilities}{$and_more ->
[0] {\"\"}
*[other] {\" \"}and {$and_more} more
}"
)]
pub(crate) struct ExpectedNames {
pub possibilities: DiagSymbolList<Ident>,
pub and_more: usize,
}
#[derive(Subdiagnostic)]
pub(crate) enum InvocationHelp {
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
)]
Cargo {
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
#[subdiagnostic]
help: Option<super::UnexpectedCfgCargoHelp>,
},
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
)]
Rustc {
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
#[subdiagnostic]
help: super::UnexpectedCfgRustcHelp,
},
}
}
#[derive(Diagnostic)]
#[diag(
"unexpected `cfg` condition value: {$has_value ->
[true] `{$value}`
*[false] (none)
}"
)]
pub(crate) struct UnexpectedCfgValue {
#[subdiagnostic]
pub code_sugg: unexpected_cfg_value::CodeSuggestion,
#[subdiagnostic]
pub invocation_help: unexpected_cfg_value::InvocationHelp,
pub has_value: bool,
pub value: String,
}
pub(crate) mod unexpected_cfg_value {
use rustc_errors::DiagSymbolList;
use rustc_macros::Subdiagnostic;
use rustc_span::{Span, Symbol};
#[derive(Subdiagnostic)]
pub(crate) enum CodeSuggestion {
ChangeValue {
#[subdiagnostic]
expected_values: ExpectedValues,
#[subdiagnostic]
suggestion: Option<ChangeValueSuggestion>,
},
#[note("no expected value for `{$name}`")]
RemoveValue {
#[subdiagnostic]
suggestion: Option<RemoveValueSuggestion>,
name: Symbol,
},
#[note("no expected values for `{$name}`")]
RemoveCondition {
#[subdiagnostic]
suggestion: RemoveConditionSuggestion,
name: Symbol,
},
ChangeName {
#[subdiagnostic]
suggestions: Vec<ChangeNameSuggestion>,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum ChangeValueSuggestion {
#[suggestion(
"there is a expected value with a similar name",
code = r#""{best_match}""#,
applicability = "maybe-incorrect"
)]
SimilarName {
#[primary_span]
span: Span,
best_match: Symbol,
},
#[suggestion(
"specify a config value",
code = r#" = "{first_possibility}""#,
applicability = "maybe-incorrect"
)]
SpecifyValue {
#[primary_span]
span: Span,
first_possibility: Symbol,
},
}
#[derive(Subdiagnostic)]
#[suggestion("remove the value", code = "", applicability = "maybe-incorrect")]
pub(crate) struct RemoveValueSuggestion {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[suggestion("remove the condition", code = "", applicability = "maybe-incorrect")]
pub(crate) struct RemoveConditionSuggestion {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[note(
"expected values for `{$name}` are: {$have_none_possibility ->
[true] {\"(none), \"}
*[false] {\"\"}
}{$possibilities}{$and_more ->
[0] {\"\"}
*[other] {\" \"}and {$and_more} more
}"
)]
pub(crate) struct ExpectedValues {
pub name: Symbol,
pub have_none_possibility: bool,
pub possibilities: DiagSymbolList,
pub and_more: usize,
}
#[derive(Subdiagnostic)]
#[suggestion(
"`{$value}` is an expected value for `{$name}`",
code = "{name}",
applicability = "maybe-incorrect",
style = "verbose"
)]
pub(crate) struct ChangeNameSuggestion {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub value: Symbol,
}
#[derive(Subdiagnostic)]
pub(crate) enum InvocationHelp {
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
)]
Cargo {
#[subdiagnostic]
help: Option<CargoHelp>,
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
},
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
)]
Rustc {
#[subdiagnostic]
help: Option<super::UnexpectedCfgRustcHelp>,
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum CargoHelp {
#[help("consider adding `{$value}` as a feature in `Cargo.toml`")]
AddFeature {
value: Symbol,
},
#[help("consider defining some features in `Cargo.toml`")]
DefineFeatures,
Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
}
}
+12 -23
View File
@@ -7,7 +7,6 @@
use rustc_errors::{Diag, DiagCtxtHandle, Level, MultiSpan};
use rustc_feature::{AttributeTemplate, Features};
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::LintId;
@@ -20,14 +19,14 @@
use crate::session_diagnostics::ParsedDescription;
use crate::{Early, Late, OmitDoc, ShouldEmit};
pub enum EmitAttribute {
Static(AttributeLintKind),
Dynamic(
Box<
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
>,
),
}
pub struct EmitAttribute(
pub Box<
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()>
+ DynSend
+ DynSync
+ 'static,
>,
);
/// Context created once, for example as part of the ast lowering
/// context, through which all attributes can be lowered.
@@ -127,13 +126,8 @@ pub fn parse_limited_all(
target,
OmitDoc::Skip,
std::convert::identity,
|lint_id, span, kind| match kind {
EmitAttribute::Static(kind) => {
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
}
EmitAttribute::Dynamic(callback) => {
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
}
|lint_id, span, kind| {
sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0)
},
)
}
@@ -214,13 +208,8 @@ pub fn parse_single_args<T, I>(
sess,
stage: Early { emit_errors },
};
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| match kind {
EmitAttribute::Static(kind) => {
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
}
EmitAttribute::Dynamic(callback) => {
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
}
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| {
sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0)
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(
+1 -1
View File
@@ -79,7 +79,7 @@ pub fn check_attribute_safety(
emit_lint(
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
path_span.into(),
EmitAttribute::Dynamic(Box::new(move |dcx, level| {
EmitAttribute(Box::new(move |dcx, level, _| {
errors::UnsafeAttrOutsideUnsafeLint {
span: path_span,
suggestion: not_from_proc_macro
+1 -1
View File
@@ -635,7 +635,7 @@ 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: DecorateDiagCompat::Dynamic(Box::new(move |dcx, level, sess| {
diagnostic: DecorateDiagCompat(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();
+12 -24
View File
@@ -5,25 +5,20 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_error_messages::MultiSpan;
use rustc_lint_defs::{AttributeLintKind, Lint, LintId};
use rustc_lint_defs::{Lint, LintId};
use crate::{Diag, DiagCtxtHandle, Diagnostic, Level};
/// 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 {
pub struct DecorateDiagCompat(
/// The third argument of the closure is a `Session`. However, due to the dependency tree,
/// we don't have access to `rustc_session` here, so we downcast it when needed.
Dynamic(
Box<
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
+ DynSync
+ DynSend
+ 'static,
>,
),
Builtin(AttributeLintKind),
}
pub Box<
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
+ DynSync
+ DynSend
+ 'static,
>,
);
impl std::fmt::Debug for DecorateDiagCompat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -34,14 +29,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
#[inline]
fn from(d: D) -> Self {
Self::Dynamic(Box::new(|dcx, level, _| d.into_diag(dcx, level)))
}
}
impl From<AttributeLintKind> for DecorateDiagCompat {
#[inline]
fn from(b: AttributeLintKind) -> Self {
Self::Builtin(b)
Self(Box::new(|dcx, level, _| d.into_diag(dcx, level)))
}
}
@@ -106,7 +94,7 @@ pub fn dyn_buffer_lint<
lint_id: LintId::of(lint),
node_id,
span: Some(span.into()),
diagnostic: DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
diagnostic: DecorateDiagCompat(Box::new(|dcx, level, _| callback(dcx, level))),
});
}
@@ -126,7 +114,7 @@ pub fn dyn_buffer_lint_any<
lint_id: LintId::of(lint),
node_id,
span: Some(span.into()),
diagnostic: DecorateDiagCompat::Dynamic(Box::new(callback)),
diagnostic: DecorateDiagCompat(Box::new(callback)),
});
}
}
-12
View File
@@ -129,18 +129,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
}
}
pub struct DiagCallback<'a>(
pub &'a Box<
dyn for<'b> Fn(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSend + DynSync + 'static,
>,
);
impl<'a, 'b> Diagnostic<'a, ()> for DiagCallback<'b> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
(self.0)(dcx, level)
}
}
/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
+2 -2
View File
@@ -36,8 +36,8 @@
pub use codes::*;
pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
pub use diagnostic::{
BugAbort, Diag, DiagCallback, DiagDecorator, DiagInner, DiagLocation, DiagStyledString,
Diagnostic, EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic,
BugAbort, Diag, DiagDecorator, DiagInner, DiagLocation, DiagStyledString, Diagnostic,
EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic,
};
pub use diagnostic_impls::{
DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
+7 -19
View File
@@ -1,7 +1,6 @@
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_error_messages::MultiSpan;
use rustc_errors::{Diag, DiagCtxtHandle, Level};
pub use rustc_lint_defs::AttributeLintKind;
use rustc_lint_defs::LintId;
use crate::HirId;
@@ -14,32 +13,21 @@
/// and then there's a gap where no lints can be emitted until HIR is done.
/// The variants in this enum represent lints that are temporarily stashed during
/// AST lowering to be emitted once HIR is built.
#[derive(Debug)]
pub enum DelayedLint {
AttributeParsing(AttributeLint),
Dynamic(DynAttribute),
}
#[derive(Debug)]
pub struct AttributeLint {
pub lint_id: LintId,
pub id: HirId,
pub span: MultiSpan,
pub kind: AttributeLintKind,
}
pub struct DynAttribute {
pub struct DelayedLint {
pub lint_id: LintId,
pub id: HirId,
pub span: MultiSpan,
pub callback: Box<
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level, &dyn std::any::Any) -> Diag<'a, ()>
+ DynSend
+ DynSync
+ 'static,
>,
}
impl std::fmt::Debug for DynAttribute {
impl std::fmt::Debug for DelayedLint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DynAttribute")
f.debug_struct("DelayedLint")
.field("lint_id", &self.lint_id)
.field("id", &self.id)
.field("span", &self.span)
+25 -29
View File
@@ -11,10 +11,12 @@
use rustc_codegen_ssa::{CompiledModules, CrateInfo};
use rustc_data_structures::indexmap::IndexMap;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal, par_fns};
use rustc_data_structures::sync::{
AppendOnlyIndexVec, DynSend, DynSync, FreezeLock, WorkerLocal, par_fns,
};
use rustc_data_structures::thousands;
use rustc_errors::DiagCallback;
use rustc_errors::timings::TimingSection;
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
use rustc_feature::Features;
use rustc_fs_util::try_canonicalize;
@@ -22,12 +24,9 @@
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
use rustc_hir::definitions::Definitions;
use rustc_hir::limit::Limit;
use rustc_hir::lints::DelayedLint;
use rustc_hir::{Attribute, MaybeOwner, Target, find_attr};
use rustc_incremental::setup_dep_graph;
use rustc_lint::{
BufferedEarlyLint, DecorateAttrLint, EarlyCheckNode, LintStore, unerased_lint_store,
};
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
use rustc_metadata::EncodedMetadata;
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
@@ -97,7 +96,6 @@ fn pre_expansion_lint<'a>(
|| {
rustc_lint::check_ast_node(
sess,
None,
features,
true,
lint_store,
@@ -141,7 +139,7 @@ fn configure_and_expand(
let tcx = resolver.tcx();
let sess = tcx.sess;
let features = tcx.features();
let lint_store = unerased_lint_store(tcx.sess);
let lint_store = unerased_lint_store(sess);
let crate_name = tcx.crate_name(LOCAL_CRATE);
let lint_check_node = (&krate, pre_configured_attrs);
pre_expansion_lint(
@@ -470,7 +468,6 @@ const fn as_str(self) -> &'static str {
let lint_store = unerased_lint_store(tcx.sess);
rustc_lint::check_ast_node(
sess,
Some(tcx),
tcx.features(),
false,
lint_store,
@@ -1028,30 +1025,29 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
)
}
struct DiagCallback<'a, 'tcx> {
callback: &'a Box<
dyn for<'b> Fn(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + DynSync,
>,
tcx: TyCtxt<'tcx>,
}
impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for DiagCallback<'b, 'tcx> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
(self.callback)(dcx, level, self.tcx.sess)
}
}
pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
for lint in delayed_lints {
match lint {
DelayedLint::AttributeParsing(attribute_lint) => {
tcx.emit_node_span_lint(
attribute_lint.lint_id.lint,
attribute_lint.id,
attribute_lint.span.clone(),
DecorateAttrLint {
sess: tcx.sess,
tcx: Some(tcx),
diagnostic: &attribute_lint.kind,
},
);
}
DelayedLint::Dynamic(attribute_lint) => tcx.emit_node_span_lint(
attribute_lint.lint_id.lint,
attribute_lint.id,
attribute_lint.span.clone(),
DiagCallback(&attribute_lint.callback),
),
}
tcx.emit_node_span_lint(
lint.lint_id.lint,
lint.id,
lint.span.clone(),
DiagCallback { callback: &lint.callback, tcx },
);
}
}
}
+17 -37
View File
@@ -7,17 +7,17 @@
use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
use rustc_ast::{self as ast, AttrVec, HasAttrs};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
use rustc_errors::{BufferedEarlyLint, LintBuffer};
use rustc_feature::Features;
use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_middle::ty::RegisteredTools;
use rustc_session::Session;
use rustc_session::lint::LintPass;
use rustc_span::{Ident, Span};
use tracing::debug;
use crate::DiagAndSess;
use crate::context::{EarlyContext, LintContext, LintStore};
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
use crate::{DecorateAttrLint, DiagAndSess};
pub(super) mod diagnostics;
@@ -27,36 +27,20 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
/// Implements the AST traversal for early lint passes. `T` provides the
/// `check_*` methods.
pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> {
pub struct EarlyContextAndPass<'ecx, T: EarlyLintPass> {
context: EarlyContext<'ecx>,
tcx: Option<TyCtxt<'tcx>>,
pass: T,
}
impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
impl<'ecx, T: EarlyLintPass> EarlyContextAndPass<'ecx, T> {
fn check_id(&mut self, id: ast::NodeId) {
for early_lint in self.context.buffered.take(id) {
let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
match diagnostic {
DecorateDiagCompat::Builtin(b) => {
self.context.opt_span_lint(
lint_id.lint,
span,
DecorateAttrLint {
sess: self.context.sess(),
tcx: self.tcx,
diagnostic: &b,
},
);
}
DecorateDiagCompat::Dynamic(callback) => {
self.context.opt_span_lint(
lint_id.lint,
span,
DiagAndSess { callback, sess: self.context.sess() },
);
}
}
self.context.opt_span_lint(
lint_id.lint,
span,
DiagAndSess { callback: diagnostic.0, sess: self.context.sess() },
);
}
}
@@ -80,9 +64,7 @@ fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'_ [ast::Attribute], f
}
}
impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
for EarlyContextAndPass<'ecx, 'tcx, T>
{
impl<'ast, 'ecx, T: EarlyLintPass> ast_visit::Visitor<'ast> for EarlyContextAndPass<'ecx, T> {
fn visit_id(&mut self, id: rustc_ast::NodeId) {
self.check_id(id);
}
@@ -297,7 +279,7 @@ impl EarlyLintPass for RuntimeCombinedEarlyLintPass<'_> {
pub trait EarlyCheckNode<'a>: Copy {
fn id(self) -> ast::NodeId;
fn attrs(self) -> &'a [ast::Attribute];
fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>);
fn check<'ecx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, T>);
}
impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
@@ -307,7 +289,7 @@ fn id(self) -> ast::NodeId {
fn attrs(self) -> &'a [ast::Attribute] {
self.1
}
fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>) {
fn check<'ecx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, T>) {
lint_callback!(cx, check_crate, self.0);
ast_visit::walk_crate(cx, self.0);
lint_callback!(cx, check_crate_post, self.0);
@@ -321,7 +303,7 @@ fn id(self) -> ast::NodeId {
fn attrs(self) -> &'a [ast::Attribute] {
self.1
}
fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>) {
fn check<'ecx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, T>) {
walk_list!(cx, visit_attribute, self.1);
walk_list!(cx, visit_item, self.2);
}
@@ -329,7 +311,6 @@ fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx,
pub fn check_ast_node<'a>(
sess: &Session,
tcx: Option<TyCtxt<'_>>,
features: &Features,
pre_expansion: bool,
lint_store: &LintStore,
@@ -353,23 +334,22 @@ pub fn check_ast_node<'a>(
let passes =
if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };
if passes.is_empty() {
check_ast_node_inner(sess, tcx, check_node, context, builtin_lints);
check_ast_node_inner(sess, check_node, context, builtin_lints);
} else {
let mut passes: Vec<_> = passes.iter().map(|mk_pass| (mk_pass)()).collect();
passes.push(Box::new(builtin_lints));
let pass = RuntimeCombinedEarlyLintPass { passes: &mut passes[..] };
check_ast_node_inner(sess, tcx, check_node, context, pass);
check_ast_node_inner(sess, check_node, context, pass);
}
}
fn check_ast_node_inner<'a, T: EarlyLintPass>(
sess: &Session,
tcx: Option<TyCtxt<'_>>,
check_node: impl EarlyCheckNode<'a>,
context: EarlyContext<'_>,
pass: T,
) {
let mut cx = EarlyContextAndPass { context, tcx, pass };
let mut cx = EarlyContextAndPass { context, pass };
cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
@@ -2,12 +2,8 @@
use rustc_data_structures::sync::DynSend;
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
use rustc_hir::lints::AttributeLintKind;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
mod check_cfg;
pub struct DiagAndSess<'sess> {
pub callback: Box<
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + 'static,
@@ -20,26 +16,3 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
(self.callback)(dcx, level, self.sess)
}
}
/// 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> {
pub sess: &'sess Session,
pub tcx: Option<TyCtxt<'tcx>>,
pub diagnostic: &'a AttributeLintKind,
}
impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
match self.diagnostic {
&AttributeLintKind::UnexpectedCfgName(name, value) => {
check_cfg::unexpected_cfg_name(self.sess, self.tcx, name, value)
.into_diag(dcx, level)
}
&AttributeLintKind::UnexpectedCfgValue(name, value) => {
check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value)
.into_diag(dcx, level)
}
}
}
}
+1 -1
View File
@@ -130,7 +130,7 @@
#[rustfmt::skip]
pub use builtin::{MissingDoc, SoftLints};
pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
pub use early::diagnostics::{DecorateAttrLint, DiagAndSess};
pub use early::diagnostics::DiagAndSess;
pub use early::{EarlyCheckNode, check_ast_node};
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
pub use levels::LintLevelsBuilder;
-372
View File
@@ -2653,378 +2653,6 @@ pub(crate) enum InvalidAsmLabel {
},
}
#[derive(Subdiagnostic)]
pub(crate) enum UnexpectedCfgCargoHelp {
#[help("consider using a Cargo feature instead")]
#[help(
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
)]
LintCfg { cargo_toml_lint_cfg: String },
#[help("consider using a Cargo feature instead")]
#[help(
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
)]
#[help("or consider adding `{$build_rs_println}` to the top of the `build.rs`")]
LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String },
}
impl UnexpectedCfgCargoHelp {
fn cargo_toml_lint_cfg(unescaped: &str) -> String {
format!(
"\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}"
)
}
pub(crate) fn lint_cfg(unescaped: &str) -> Self {
UnexpectedCfgCargoHelp::LintCfg {
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
}
}
pub(crate) fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self {
UnexpectedCfgCargoHelp::LintCfgAndBuildRs {
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"),
}
}
}
#[derive(Subdiagnostic)]
#[help("to expect this configuration use `{$cmdline_arg}`")]
pub(crate) struct UnexpectedCfgRustcHelp {
pub cmdline_arg: String,
}
impl UnexpectedCfgRustcHelp {
pub(crate) fn new(unescaped: &str) -> Self {
Self { cmdline_arg: format!("--check-cfg={unescaped}") }
}
}
#[derive(Subdiagnostic)]
#[note(
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
)]
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
pub(crate) struct UnexpectedCfgRustcMacroHelp {
pub macro_kind: &'static str,
pub macro_name: Symbol,
}
#[derive(Subdiagnostic)]
#[note(
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
)]
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
#[help(
"the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}`"
)]
pub(crate) struct UnexpectedCfgCargoMacroHelp {
pub macro_kind: &'static str,
pub macro_name: Symbol,
pub crate_name: Symbol,
}
#[derive(Diagnostic)]
#[diag("unexpected `cfg` condition name: `{$name}`")]
pub(crate) struct UnexpectedCfgName {
#[subdiagnostic]
pub code_sugg: unexpected_cfg_name::CodeSuggestion,
#[subdiagnostic]
pub invocation_help: unexpected_cfg_name::InvocationHelp,
pub name: Symbol,
}
pub(crate) mod unexpected_cfg_name {
use rustc_errors::DiagSymbolList;
use rustc_macros::Subdiagnostic;
use rustc_span::{Ident, Span, Symbol};
#[derive(Subdiagnostic)]
pub(crate) enum CodeSuggestion {
#[help("consider defining some features in `Cargo.toml`")]
DefineFeatures,
#[multipart_suggestion(
"there is a similar config predicate: `version(\"..\")`",
applicability = "machine-applicable"
)]
VersionSyntax {
#[suggestion_part(code = "(")]
between_name_and_value: Span,
#[suggestion_part(code = ")")]
after_value: Span,
},
#[suggestion(
"there is a config with a similar name and value",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarNameAndValue {
#[primary_span]
span: Span,
code: String,
},
#[suggestion(
"there is a config with a similar name and no value",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarNameNoValue {
#[primary_span]
span: Span,
code: String,
},
#[suggestion(
"there is a config with a similar name and different values",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarNameDifferentValues {
#[primary_span]
span: Span,
code: String,
#[subdiagnostic]
expected: Option<ExpectedValues>,
},
#[suggestion(
"there is a config with a similar name",
applicability = "maybe-incorrect",
code = "{code}"
)]
SimilarName {
#[primary_span]
span: Span,
code: String,
#[subdiagnostic]
expected: Option<ExpectedValues>,
},
SimilarValues {
#[subdiagnostic]
with_similar_values: Vec<FoundWithSimilarValue>,
#[subdiagnostic]
expected_names: Option<ExpectedNames>,
},
#[suggestion(
"you may have meant to use `{$literal}` (notice the capitalization). Doing so makes this predicate evaluate to `{$literal}` unconditionally",
applicability = "machine-applicable",
style = "verbose",
code = "{literal}"
)]
BooleanLiteral {
#[primary_span]
span: Span,
literal: bool,
},
}
#[derive(Subdiagnostic)]
#[help("expected values for `{$best_match}` are: {$possibilities}")]
pub(crate) struct ExpectedValues {
pub best_match: Symbol,
pub possibilities: DiagSymbolList,
}
#[derive(Subdiagnostic)]
#[suggestion(
"found config with similar value",
applicability = "maybe-incorrect",
code = "{code}"
)]
pub(crate) struct FoundWithSimilarValue {
#[primary_span]
pub span: Span,
pub code: String,
}
#[derive(Subdiagnostic)]
#[help_once(
"expected names are: {$possibilities}{$and_more ->
[0] {\"\"}
*[other] {\" \"}and {$and_more} more
}"
)]
pub(crate) struct ExpectedNames {
pub possibilities: DiagSymbolList<Ident>,
pub and_more: usize,
}
#[derive(Subdiagnostic)]
pub(crate) enum InvocationHelp {
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
)]
Cargo {
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
#[subdiagnostic]
help: Option<super::UnexpectedCfgCargoHelp>,
},
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
)]
Rustc {
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
#[subdiagnostic]
help: super::UnexpectedCfgRustcHelp,
},
}
}
#[derive(Diagnostic)]
#[diag(
"unexpected `cfg` condition value: {$has_value ->
[true] `{$value}`
*[false] (none)
}"
)]
pub(crate) struct UnexpectedCfgValue {
#[subdiagnostic]
pub code_sugg: unexpected_cfg_value::CodeSuggestion,
#[subdiagnostic]
pub invocation_help: unexpected_cfg_value::InvocationHelp,
pub has_value: bool,
pub value: String,
}
pub(crate) mod unexpected_cfg_value {
use rustc_errors::DiagSymbolList;
use rustc_macros::Subdiagnostic;
use rustc_span::{Span, Symbol};
#[derive(Subdiagnostic)]
pub(crate) enum CodeSuggestion {
ChangeValue {
#[subdiagnostic]
expected_values: ExpectedValues,
#[subdiagnostic]
suggestion: Option<ChangeValueSuggestion>,
},
#[note("no expected value for `{$name}`")]
RemoveValue {
#[subdiagnostic]
suggestion: Option<RemoveValueSuggestion>,
name: Symbol,
},
#[note("no expected values for `{$name}`")]
RemoveCondition {
#[subdiagnostic]
suggestion: RemoveConditionSuggestion,
name: Symbol,
},
ChangeName {
#[subdiagnostic]
suggestions: Vec<ChangeNameSuggestion>,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum ChangeValueSuggestion {
#[suggestion(
"there is a expected value with a similar name",
code = r#""{best_match}""#,
applicability = "maybe-incorrect"
)]
SimilarName {
#[primary_span]
span: Span,
best_match: Symbol,
},
#[suggestion(
"specify a config value",
code = r#" = "{first_possibility}""#,
applicability = "maybe-incorrect"
)]
SpecifyValue {
#[primary_span]
span: Span,
first_possibility: Symbol,
},
}
#[derive(Subdiagnostic)]
#[suggestion("remove the value", code = "", applicability = "maybe-incorrect")]
pub(crate) struct RemoveValueSuggestion {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[suggestion("remove the condition", code = "", applicability = "maybe-incorrect")]
pub(crate) struct RemoveConditionSuggestion {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[note(
"expected values for `{$name}` are: {$have_none_possibility ->
[true] {\"(none), \"}
*[false] {\"\"}
}{$possibilities}{$and_more ->
[0] {\"\"}
*[other] {\" \"}and {$and_more} more
}"
)]
pub(crate) struct ExpectedValues {
pub name: Symbol,
pub have_none_possibility: bool,
pub possibilities: DiagSymbolList,
pub and_more: usize,
}
#[derive(Subdiagnostic)]
#[suggestion(
"`{$value}` is an expected value for `{$name}`",
code = "{name}",
applicability = "maybe-incorrect",
style = "verbose"
)]
pub(crate) struct ChangeNameSuggestion {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub value: Symbol,
}
#[derive(Subdiagnostic)]
pub(crate) enum InvocationHelp {
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
)]
Cargo {
#[subdiagnostic]
help: Option<CargoHelp>,
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
},
#[note(
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
)]
Rustc {
#[subdiagnostic]
help: Option<super::UnexpectedCfgRustcHelp>,
#[subdiagnostic]
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum CargoHelp {
#[help("consider adding `{$value}` as a feature in `Cargo.toml`")]
AddFeature {
value: Symbol,
},
#[help("consider defining some features in `Cargo.toml`")]
DefineFeatures,
Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
}
}
#[derive(Diagnostic)]
#[diag("creating a {$shared_label}reference to mutable static")]
pub(crate) struct RefOfMutStatic<'a> {
+1 -7
View File
@@ -12,7 +12,7 @@
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::DefPathHash;
pub use rustc_span::edition::Edition;
use rustc_span::{HashStableContext, Ident, Span, Symbol, sym};
use rustc_span::{HashStableContext, Ident, Symbol, sym};
use serde::{Deserialize, Serialize};
pub use self::Level::*;
@@ -652,12 +652,6 @@ pub enum DeprecatedSinceKind {
InVersion(String),
}
#[derive(Debug)]
pub enum AttributeLintKind {
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
}
pub type RegisteredTools = FxIndexSet<Ident>;
/// Declares a static item of type `&'static Lint`.
+24 -1
View File
@@ -344,7 +344,30 @@ pub fn dyn_buffer_lint<
lint,
Some(span.into()),
node_id,
DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
DecorateDiagCompat(Box::new(|dcx, level, _| callback(dcx, level))),
)
}
pub fn dyn_buffer_lint_sess<
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()>
+ DynSync
+ DynSend
+ 'static,
>(
&self,
lint: &'static Lint,
span: impl Into<MultiSpan>,
node_id: NodeId,
callback: F,
) {
self.opt_span_buffer_lint(
lint,
Some(span.into()),
node_id,
DecorateDiagCompat(Box::new(|dcx, level, sess| {
let sess = sess.downcast_ref::<Session>().expect("expected a `Session`");
callback(dcx, level, sess)
})),
)
}
@@ -7,7 +7,6 @@ LL | cfg_macro::my_lib_macro!();
= help: expected names are: `feature` and 32 more
= note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
= help: try referring to `cfg_macro::my_lib_macro` crate for guidance on how handle this unexpected cfg
= help: the macro `cfg_macro::my_lib_macro` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
= note: `#[warn(unexpected_cfgs)]` on by default
= note: this warning originates in the macro `cfg_macro::my_lib_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -21,7 +20,6 @@ LL | cfg_macro::my_lib_macro_value!();
= note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind`
= note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
= help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg
= help: the macro `cfg_macro::my_lib_macro_value` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
= note: this warning originates in the macro `cfg_macro::my_lib_macro_value` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -34,7 +32,6 @@ LL | cfg_macro::my_lib_macro_feature!();
= note: no expected values for `feature`
= note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
= help: try referring to `cfg_macro::my_lib_macro_feature` crate for guidance on how handle this unexpected cfg
= help: the macro `cfg_macro::my_lib_macro_feature` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
= note: this warning originates in the macro `cfg_macro::my_lib_macro_feature` (in Nightly builds, run with -Z macro-backtrace for more info)
+1 -1
View File
@@ -1053,7 +1053,7 @@ cc = ["@Nadrieril"]
message = "Some changes occurred in cfg and check-cfg configuration"
cc = ["@Urgau"]
[mentions."compiler/rustc_lint/src/early/diagnostics/check_cfg.rs"]
[mentions."compiler/rustc_attr_parsing/src/attributes/diagnostic/check_cfg.rs"]
message = "Some changes occurred in check-cfg diagnostics"
cc = ["@Urgau"]