Skip to content

Commit 71b093f

Browse files
Emit check-cfg lints during attribute parsing rather than evaluation#149215
1 parent fbab541 commit 71b093f

File tree

12 files changed

+64
-123
lines changed

12 files changed

+64
-123
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 29 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ use std::convert::identity;
22

33
use rustc_ast::token::Delimiter;
44
use rustc_ast::tokenstream::DelimSpan;
5-
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token};
5+
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
66
use rustc_errors::{Applicability, PResult};
77
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template};
88
use rustc_hir::attrs::CfgEntry;
9+
use rustc_hir::lints::AttributeLintKind;
910
use rustc_hir::{AttrPath, RustcVersion};
1011
use rustc_parse::parser::{ForceCollect, Parser};
1112
use rustc_parse::{exp, parse_in};
1213
use rustc_session::Session;
1314
use rustc_session::config::ExpectedValues;
14-
use rustc_session::lint::BuiltinLintDiag;
1515
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
1616
use rustc_session::parse::{ParseSess, feature_err};
1717
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
@@ -23,10 +23,7 @@ use crate::session_diagnostics::{
2323
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
2424
ParsedDescription,
2525
};
26-
use crate::{
27-
AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics,
28-
try_gate_cfg,
29-
};
26+
use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg};
3027

3128
pub const CFG_TEMPLATE: AttributeTemplate = template!(
3229
List: &["predicate"],
@@ -195,43 +192,46 @@ fn parse_name_value<S: Stage>(
195192
}
196193
};
197194

198-
Ok(CfgEntry::NameValue { name, name_span, value, span })
195+
match cx.sess.psess.check_config.expecteds.get(&name) {
196+
Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx
197+
.emit_lint(
198+
UNEXPECTED_CFGS,
199+
AttributeLintKind::UnexpectedCfgValue((name, name_span), value),
200+
span,
201+
),
202+
None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint(
203+
UNEXPECTED_CFGS,
204+
AttributeLintKind::UnexpectedCfgName((name, name_span), value),
205+
span,
206+
),
207+
_ => { /* not unexpected */ }
208+
}
209+
210+
Ok(CfgEntry::NameValue { name, value: value.map(|(v, _)| v), span })
199211
}
200212

201-
pub fn eval_config_entry(
202-
sess: &Session,
203-
cfg_entry: &CfgEntry,
204-
id: NodeId,
205-
emit_lints: ShouldEmit,
206-
) -> EvalConfigResult {
213+
pub fn eval_config_entry(sess: &Session, cfg_entry: &CfgEntry) -> EvalConfigResult {
207214
match cfg_entry {
208215
CfgEntry::All(subs, ..) => {
209-
let mut all = None;
210216
for sub in subs {
211-
let res = eval_config_entry(sess, sub, id, emit_lints);
212-
// We cannot short-circuit because `eval_config_entry` emits some lints
217+
let res = eval_config_entry(sess, sub);
213218
if !res.as_bool() {
214-
all.get_or_insert(res);
219+
return res;
215220
}
216221
}
217-
all.unwrap_or_else(|| EvalConfigResult::True)
222+
EvalConfigResult::True
218223
}
219224
CfgEntry::Any(subs, span) => {
220-
let mut any = None;
221225
for sub in subs {
222-
let res = eval_config_entry(sess, sub, id, emit_lints);
223-
// We cannot short-circuit because `eval_config_entry` emits some lints
226+
let res = eval_config_entry(sess, sub);
224227
if res.as_bool() {
225-
any.get_or_insert(res);
228+
return res;
226229
}
227230
}
228-
any.unwrap_or_else(|| EvalConfigResult::False {
229-
reason: cfg_entry.clone(),
230-
reason_span: *span,
231-
})
231+
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
232232
}
233233
CfgEntry::Not(sub, span) => {
234-
if eval_config_entry(sess, sub, id, emit_lints).as_bool() {
234+
if eval_config_entry(sess, sub).as_bool() {
235235
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
236236
} else {
237237
EvalConfigResult::True
@@ -244,32 +244,8 @@ pub fn eval_config_entry(
244244
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }
245245
}
246246
}
247-
CfgEntry::NameValue { name, name_span, value, span } => {
248-
if let ShouldEmit::ErrorsAndLints = emit_lints {
249-
match sess.psess.check_config.expecteds.get(name) {
250-
Some(ExpectedValues::Some(values))
251-
if !values.contains(&value.map(|(v, _)| v)) =>
252-
{
253-
id.emit_span_lint(
254-
sess,
255-
UNEXPECTED_CFGS,
256-
*span,
257-
BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value),
258-
);
259-
}
260-
None if sess.psess.check_config.exhaustive_names => {
261-
id.emit_span_lint(
262-
sess,
263-
UNEXPECTED_CFGS,
264-
*span,
265-
BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value),
266-
);
267-
}
268-
_ => { /* not unexpected */ }
269-
}
270-
}
271-
272-
if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) {
247+
CfgEntry::NameValue { name, value, span } => {
248+
if sess.psess.config.contains(&(*name, *value)) {
273249
EvalConfigResult::True
274250
} else {
275251
EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span }

compiler/rustc_attr_parsing/src/attributes/cfg_old.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, Nod
22
use rustc_ast_pretty::pprust;
33
use rustc_feature::{Features, GatedCfg, find_gated_cfg};
44
use rustc_hir::RustcVersion;
5+
use rustc_hir::lints::AttributeLintKind;
56
use rustc_session::Session;
67
use rustc_session::config::ExpectedValues;
78
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
@@ -51,21 +52,21 @@ pub fn cfg_matches(
5152
sess,
5253
UNEXPECTED_CFGS,
5354
cfg.span,
54-
BuiltinLintDiag::UnexpectedCfgValue(
55+
BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgValue(
5556
(cfg.name, cfg.name_span),
5657
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
57-
),
58+
)),
5859
);
5960
}
6061
None if sess.psess.check_config.exhaustive_names => {
6162
lint_emitter.emit_span_lint(
6263
sess,
6364
UNEXPECTED_CFGS,
6465
cfg.span,
65-
BuiltinLintDiag::UnexpectedCfgName(
66+
BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgName(
6667
(cfg.name, cfg.name_span),
6768
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
68-
),
69+
)),
6970
);
7071
}
7172
_ => { /* not unexpected */ }

compiler/rustc_builtin_macros/src/cfg.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,7 @@ pub(crate) fn expand_cfg(
2626

2727
ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
2828
Ok(cfg) => {
29-
let matches_cfg = attr::eval_config_entry(
30-
cx.sess,
31-
&cfg,
32-
cx.current_expansion.lint_node_id,
33-
ShouldEmit::ErrorsAndLints,
34-
)
35-
.as_bool();
29+
let matches_cfg = attr::eval_config_entry(cx.sess, &cfg).as_bool();
3630

3731
MacEager::expr(cx.expr_bool(sp, matches_cfg))
3832
}

compiler/rustc_builtin_macros/src/cfg_select.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_ast::tokenstream::TokenStream;
22
use rustc_attr_parsing as attr;
33
use rustc_attr_parsing::{
4-
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select,
4+
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
55
};
66
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
77
use rustc_span::{Ident, Span, sym};
@@ -10,21 +10,13 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
1010

1111
/// Selects the first arm whose predicate evaluates to true.
1212
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
13-
let mut result = None;
1413
for (cfg, tt, arm_span) in branches.reachable {
15-
if let EvalConfigResult::True = attr::eval_config_entry(
16-
&ecx.sess,
17-
&cfg,
18-
ecx.current_expansion.lint_node_id,
19-
ShouldEmit::ErrorsAndLints,
20-
) {
21-
// FIXME(#149215) Ideally we should short-circuit here, but `eval_config_entry` currently emits lints so we cannot do this yet.
22-
result.get_or_insert((tt, arm_span));
14+
if let EvalConfigResult::True = attr::eval_config_entry(&ecx.sess, &cfg) {
15+
return Some((tt, arm_span));
2316
}
2417
}
2518

26-
let wildcard = branches.wildcard.map(|(_, tt, span)| (tt, span));
27-
result.or(wildcard)
19+
branches.wildcard.map(|(_, tt, span)| (tt, span))
2820
}
2921

3022
pub(super) fn expand_cfg_select<'cx>(

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use find_msvc_tools;
1313
use itertools::Itertools;
1414
use regex::Regex;
1515
use rustc_arena::TypedArena;
16-
use rustc_ast::CRATE_NODE_ID;
17-
use rustc_attr_parsing::{ShouldEmit, eval_config_entry};
16+
use rustc_attr_parsing::eval_config_entry;
1817
use rustc_data_structures::fx::FxIndexSet;
1918
use rustc_data_structures::memmap::Mmap;
2019
use rustc_data_structures::temp_dir::MaybeTempDir;
@@ -3029,9 +3028,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
30293028

30303029
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
30313030
match lib.cfg {
3032-
Some(ref cfg) => {
3033-
eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool()
3034-
}
3031+
Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(),
30353032
None => true,
30363033
}
30373034
}

compiler/rustc_expand/src/config.rs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,7 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
163163
.iter()
164164
.flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
165165
.take_while(|attr| {
166-
!is_cfg(attr)
167-
|| strip_unconfigured
168-
.cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing)
169-
.as_bool()
166+
!is_cfg(attr) || strip_unconfigured.cfg_true(attr, ShouldEmit::Nothing).as_bool()
170167
})
171168
.collect()
172169
}
@@ -309,14 +306,7 @@ impl<'a> StripUnconfigured<'a> {
309306
);
310307
}
311308

312-
if !attr::eval_config_entry(
313-
self.sess,
314-
&cfg_predicate,
315-
ast::CRATE_NODE_ID,
316-
ShouldEmit::ErrorsAndLints,
317-
)
318-
.as_bool()
319-
{
309+
if !attr::eval_config_entry(self.sess, &cfg_predicate).as_bool() {
320310
return vec![trace_attr];
321311
}
322312

@@ -400,23 +390,17 @@ impl<'a> StripUnconfigured<'a> {
400390

401391
/// Determines if a node with the given attributes should be included in this configuration.
402392
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
403-
attrs.iter().all(|attr| {
404-
!is_cfg(attr)
405-
|| self.cfg_true(attr, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool()
406-
})
393+
attrs
394+
.iter()
395+
.all(|attr| !is_cfg(attr) || self.cfg_true(attr, ShouldEmit::ErrorsAndLints).as_bool())
407396
}
408397

409-
pub(crate) fn cfg_true(
410-
&self,
411-
attr: &Attribute,
412-
node: NodeId,
413-
emit_errors: ShouldEmit,
414-
) -> EvalConfigResult {
398+
pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> EvalConfigResult {
415399
let Some(cfg) = AttributeParser::parse_single(
416400
self.sess,
417401
attr,
418402
attr.span,
419-
node,
403+
self.lint_node_id,
420404
self.features,
421405
emit_errors,
422406
parse_cfg,
@@ -426,7 +410,7 @@ impl<'a> StripUnconfigured<'a> {
426410
return EvalConfigResult::True;
427411
};
428412

429-
eval_config_entry(self.sess, &cfg, self.lint_node_id, emit_errors)
413+
eval_config_entry(self.sess, &cfg)
430414
}
431415

432416
/// If attributes are not allowed on expressions, emit an error for `attr`

compiler/rustc_expand/src/expand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2213,7 +2213,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
22132213
attr: ast::Attribute,
22142214
pos: usize,
22152215
) -> EvalConfigResult {
2216-
let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints);
2216+
let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints);
22172217
if res.as_bool() {
22182218
// A trace attribute left in AST in place of the original `cfg` attribute.
22192219
// It can later be used by lints or other diagnostics.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pub enum CfgEntry {
190190
Any(ThinVec<CfgEntry>, Span),
191191
Not(Box<CfgEntry>, Span),
192192
Bool(bool, Span),
193-
NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span },
193+
NameValue { name: Symbol, value: Option<Symbol>, span: Span },
194194
Version(Option<RustcVersion>, Span),
195195
}
196196

compiler/rustc_lint/src/early/diagnostics.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,6 @@ pub fn decorate_builtin_lint(
169169
}
170170
.decorate_lint(diag);
171171
}
172-
BuiltinLintDiag::UnexpectedCfgName(name, value) => {
173-
check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag);
174-
}
175-
BuiltinLintDiag::UnexpectedCfgValue(name, value) => {
176-
check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag);
177-
}
178172
BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
179173
let suggestion = match sugg {
180174
Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
@@ -307,8 +301,8 @@ pub fn decorate_builtin_lint(
307301
}
308302

309303
pub fn decorate_attribute_lint(
310-
_sess: &Session,
311-
_tcx: Option<TyCtxt<'_>>,
304+
sess: &Session,
305+
tcx: Option<TyCtxt<'_>>,
312306
kind: &AttributeLintKind,
313307
diag: &mut Diag<'_, ()>,
314308
) {
@@ -364,5 +358,11 @@ pub fn decorate_attribute_lint(
364358
suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right },
365359
}
366360
.decorate_lint(diag),
361+
&AttributeLintKind::UnexpectedCfgName(name, value) => {
362+
check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag)
363+
}
364+
&AttributeLintKind::UnexpectedCfgValue(name, value) => {
365+
check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag)
366+
}
367367
}
368368
}

compiler/rustc_lint_defs/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,8 +636,6 @@ pub enum BuiltinLintDiag {
636636
},
637637
BreakWithLabelAndLoop(Span),
638638
UnicodeTextFlow(Span, String),
639-
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
640-
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
641639
DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
642640
SingleUseLifetime {
643641
/// Span of the parameter which declares this lifetime.
@@ -732,6 +730,8 @@ pub enum AttributeLintKind {
732730
attribute_name_span: Span,
733731
sugg_spans: (Span, Span),
734732
},
733+
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
734+
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
735735
}
736736

737737
pub type RegisteredTools = FxIndexSet<Ident>;

0 commit comments

Comments
 (0)