Skip to content
Draft
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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3533,6 +3533,7 @@ dependencies = [
"rustc_hir",
"rustc_lexer",
"rustc_macros",
"rustc_middle",
"rustc_parse",
"rustc_session",
"rustc_span",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
Expand Down
42 changes: 42 additions & 0 deletions compiler/rustc_attr_parsing/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,48 @@ attr_parsing_stability_outside_std = stability attributes may not be used outsid
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)

attr_parsing_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs`
attr_parsing_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
attr_parsing_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
attr_parsing_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}`

attr_parsing_unexpected_cfg_define_features = consider defining some features in `Cargo.toml`
attr_parsing_unexpected_cfg_doc_cargo = see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
attr_parsing_unexpected_cfg_doc_rustc = see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration

attr_parsing_unexpected_cfg_from_external_macro_origin = using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate
attr_parsing_unexpected_cfg_from_external_macro_refer = try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg
attr_parsing_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}`
attr_parsing_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more ->
[0] {""}
*[other] {" "}and {$and_more} more
}
attr_parsing_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities}
attr_parsing_unexpected_cfg_name_similar_name = there is a config with a similar name
attr_parsing_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values
attr_parsing_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value
attr_parsing_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value
attr_parsing_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")`
attr_parsing_unexpected_cfg_name_with_similar_value = found config with similar value

attr_parsing_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value ->
[true] `{$value}`
*[false] (none)
}
attr_parsing_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml`
attr_parsing_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility ->
[true] {"(none), "}
*[false] {""}
}{$possibilities}{$and_more ->
[0] {""}
*[other] {" "}and {$and_more} more
}
attr_parsing_unexpected_cfg_value_no_expected_value = no expected value for `{$name}`
attr_parsing_unexpected_cfg_value_no_expected_values = no expected values for `{$name}`
attr_parsing_unexpected_cfg_value_remove_condition = remove the condition
attr_parsing_unexpected_cfg_value_remove_value = remove the value
attr_parsing_unexpected_cfg_value_similar_name = there is a expected value with a similar name
attr_parsing_unexpected_cfg_value_specify_value = specify a config value
attr_parsing_unknown_meta_item =
unknown meta item '{$item}'
.label = expected one of {$expected}
Expand Down
77 changes: 24 additions & 53 deletions compiler/rustc_attr_parsing/src/attributes/cfg.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
pub(crate) mod check_cfg;

use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token};
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
use rustc_errors::{Applicability, PResult};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, RustcVersion};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::{exp, parse_in};
use rustc_session::Session;
use rustc_session::config::ExpectedValues;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::parse::{ParseSess, feature_err};
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use thin_vec::ThinVec;
Expand All @@ -21,10 +22,7 @@ use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
ParsedDescription,
};
use crate::{
AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics,
try_gate_cfg,
};
use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg};

pub const CFG_TEMPLATE: AttributeTemplate = template!(
List: &["predicate"],
Expand Down Expand Up @@ -193,43 +191,40 @@ 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(AttributeLintKind::UnexpectedCfgValue { name, name_span, value }, span);
}
None if cx.sess.psess.check_config.exhaustive_names => {
cx.emit_lint(AttributeLintKind::UnexpectedCfgName { name, name_span, value }, span);
}
_ => { /* not unexpected */ }
}

Ok(CfgEntry::NameValue { name, name_span, value, span })
}

pub fn eval_config_entry(
sess: &Session,
cfg_entry: &CfgEntry,
id: NodeId,
emit_lints: ShouldEmit,
) -> EvalConfigResult {
pub fn eval_config_entry(sess: &Session, cfg_entry: &CfgEntry) -> EvalConfigResult {
match cfg_entry {
CfgEntry::All(subs, ..) => {
let mut all = None;
for sub in subs {
let res = eval_config_entry(sess, sub, id, emit_lints);
// We cannot short-circuit because `eval_config_entry` emits some lints
let res = eval_config_entry(sess, sub);
if !res.as_bool() {
all.get_or_insert(res);
return res;
}
}
all.unwrap_or_else(|| EvalConfigResult::True)
EvalConfigResult::True
}
CfgEntry::Any(subs, span) => {
let mut any = None;
for sub in subs {
let res = eval_config_entry(sess, sub, id, emit_lints);
// We cannot short-circuit because `eval_config_entry` emits some lints
if res.as_bool() {
any.get_or_insert(res);
if eval_config_entry(sess, sub).as_bool() {
return EvalConfigResult::True;
}
}
any.unwrap_or_else(|| EvalConfigResult::False {
reason: cfg_entry.clone(),
reason_span: *span,
})
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
}
CfgEntry::Not(sub, span) => {
if eval_config_entry(sess, sub, id, emit_lints).as_bool() {
if eval_config_entry(sess, sub).as_bool() {
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
} else {
EvalConfigResult::True
Expand All @@ -242,31 +237,7 @@ pub fn eval_config_entry(
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
}
}
CfgEntry::NameValue { name, name_span, value, span } => {
if let ShouldEmit::ErrorsAndLints = emit_lints {
match sess.psess.check_config.expecteds.get(name) {
Some(ExpectedValues::Some(values))
if !values.contains(&value.map(|(v, _)| v)) =>
{
id.emit_span_lint(
sess,
UNEXPECTED_CFGS,
*span,
BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
);
}
None if sess.psess.check_config.exhaustive_names => {
id.emit_span_lint(
sess,
UNEXPECTED_CFGS,
*span,
BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
);
}
_ => { /* not unexpected */ }
}
}

CfgEntry::NameValue { name, name_span: _, value, span } => {
if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) {
EvalConfigResult::True
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
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::edit_distance::find_best_match_for_name;
use rustc_span::{ExpnKind, Ident, Span, Symbol, sym};

use crate::lints;
use crate::session_diagnostics as lints;

const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;

Expand Down Expand Up @@ -89,29 +88,20 @@ fn rustc_macro_help(span: Span) -> Option<lints::UnexpectedCfgRustcMacroHelp> {
}
}

fn cargo_macro_help(
tcx: Option<TyCtxt<'_>>,
span: Span,
) -> Option<lints::UnexpectedCfgCargoMacroHelp> {
fn cargo_macro_help(span: Span) -> Option<lints::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
{
Some(lints::UnexpectedCfgCargoMacroHelp {
macro_kind: macro_kind.descr(),
macro_name,
crate_name: tcx.crate_name(def_id.krate),
})
Some(lints::UnexpectedCfgCargoMacroHelp { macro_kind: macro_kind.descr(), macro_name })
} else {
None
}
}

pub(super) fn unexpected_cfg_name(
pub fn unexpected_cfg_name(
sess: &Session,
tcx: Option<TyCtxt<'_>>,
(name, name_span): (Symbol, Span),
value: Option<(Symbol, Span)>,
) -> lints::UnexpectedCfgName {
Expand Down Expand Up @@ -253,7 +243,7 @@ pub(super) fn unexpected_cfg_name(
};
lints::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));
Expand All @@ -266,9 +256,8 @@ pub(super) fn unexpected_cfg_name(
lints::UnexpectedCfgName { code_sugg, invocation_help, name }
}

pub(super) fn unexpected_cfg_value(
pub fn unexpected_cfg_value(
sess: &Session,
tcx: Option<TyCtxt<'_>>,
(name, name_span): (Symbol, Span),
value: Option<(Symbol, Span)>,
) -> lints::UnexpectedCfgValue {
Expand Down Expand Up @@ -353,7 +342,7 @@ pub(super) fn unexpected_cfg_value(
// basic heuristic, we use the "cheat" unstable feature enable method and the
// non-ui-testing enabled option.
|| (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat)
&& !sess.opts.unstable_opts.ui_testing);
&& !sess.opts.unstable_opts.ui_testing);

let inst = |escape_quotes| {
to_check_cfg_arg(Ident::new(name, name_span), value.map(|(v, _s)| v), escape_quotes)
Expand All @@ -373,7 +362,7 @@ pub(super) fn unexpected_cfg_value(
};
lints::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 {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl<'sess> AttributeParser<'sess, Early> {
OmitDoc::Skip,
std::convert::identity,
|lint| {
crate::lints::emit_attribute_lint(&lint, sess);
crate::lints::emit_attribute_lint(&lint, sess, sess);
},
)
}
Expand Down Expand Up @@ -187,7 +187,7 @@ impl<'sess> AttributeParser<'sess, Early> {
target_span,
target_id: target_node_id,
emit_lint: &mut |lint| {
crate::lints::emit_attribute_lint(&lint, sess);
crate::lints::emit_attribute_lint(&lint, sess, sess);
},
},
attr_span,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ mod session_diagnostics;
mod target_checking;
pub mod validate_attr;

pub use attributes::cfg::check_cfg::{unexpected_cfg_name, unexpected_cfg_value};
pub use attributes::cfg::{
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
};
Expand Down
24 changes: 22 additions & 2 deletions compiler/rustc_attr_parsing/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ use std::borrow::Cow;
use rustc_errors::{DiagArgValue, LintEmitter};
use rustc_hir::Target;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_session::Session;
use rustc_span::sym;

use crate::session_diagnostics;
use crate::{session_diagnostics, unexpected_cfg_name, unexpected_cfg_value};

pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emitter: L) {
//tcx: TyCtxt<'_>
pub fn emit_attribute_lint<L: LintEmitter>(
lint: &AttributeLint<L::Id>,
lint_emitter: L,
sess: &Session,
) {
let AttributeLint { id, span, kind } = lint;

match kind {
Expand Down Expand Up @@ -98,5 +104,19 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi
},
)
}
&AttributeLintKind::UnexpectedCfgName { name, name_span, value } => lint_emitter
.emit_node_span_lint(
rustc_session::lint::builtin::UNEXPECTED_CFGS,
*id,
*span,
unexpected_cfg_name(sess, (name, name_span), value),
),
&AttributeLintKind::UnexpectedCfgValue { name, name_span, value } => lint_emitter
.emit_node_span_lint(
rustc_session::lint::builtin::UNEXPECTED_CFGS,
*id,
*span,
unexpected_cfg_value(sess, (name, name_span), value),
),
}
}
Loading
Loading