Skip to content

Commit d327d5b

Browse files
committed
Improve internal representation of check-cfg
This is done to simplify to relationship between names() and values() but also make thing clearer (having an Any to represent that any values are allowed) but also to allow the (none) + values expected cases that wasn't possible before.
1 parent ad6f4b7 commit d327d5b

File tree

5 files changed

+173
-153
lines changed

5 files changed

+173
-153
lines changed

compiler/rustc_attr/src/builtin.rs

+16-18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedM
55
use rustc_ast_pretty::pprust;
66
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
77
use rustc_macros::HashStable_Generic;
8+
use rustc_session::config::ExpectedValues;
89
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
910
use rustc_session::lint::BuiltinLintDiagnostics;
1011
use rustc_session::parse::{feature_err, ParseSess};
@@ -581,8 +582,20 @@ pub fn cfg_matches(
581582
) -> bool {
582583
eval_condition(cfg, sess, features, &mut |cfg| {
583584
try_gate_cfg(cfg.name, cfg.span, sess, features);
584-
if let Some(names_valid) = &sess.check_config.names_valid {
585-
if !names_valid.contains(&cfg.name) {
585+
match sess.check_config.expecteds.get(&cfg.name) {
586+
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
587+
sess.buffer_lint_with_diagnostic(
588+
UNEXPECTED_CFGS,
589+
cfg.span,
590+
lint_node_id,
591+
"unexpected `cfg` condition value",
592+
BuiltinLintDiagnostics::UnexpectedCfg(
593+
(cfg.name, cfg.name_span),
594+
cfg.value_span.map(|vs| (cfg.value.unwrap(), vs)),
595+
),
596+
);
597+
}
598+
None if sess.check_config.exhaustive_names => {
586599
sess.buffer_lint_with_diagnostic(
587600
UNEXPECTED_CFGS,
588601
cfg.span,
@@ -591,22 +604,7 @@ pub fn cfg_matches(
591604
BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
592605
);
593606
}
594-
}
595-
if let Some(value) = cfg.value {
596-
if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
597-
if !values.contains(&value) {
598-
sess.buffer_lint_with_diagnostic(
599-
UNEXPECTED_CFGS,
600-
cfg.span,
601-
lint_node_id,
602-
"unexpected `cfg` condition value",
603-
BuiltinLintDiagnostics::UnexpectedCfg(
604-
(cfg.name, cfg.name_span),
605-
cfg.value_span.map(|vs| (value, vs)),
606-
),
607-
);
608-
}
609-
}
607+
_ => { /* not unexpected */ }
610608
}
611609
sess.config.contains(&(cfg.name, cfg.value))
612610
})

compiler/rustc_interface/src/interface.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_data_structures::OnDrop;
99
use rustc_errors::registry::Registry;
1010
use rustc_errors::{ErrorGuaranteed, Handler};
1111
use rustc_lint::LintStore;
12-
use rustc_middle::ty;
12+
use rustc_middle::{bug, ty};
1313
use rustc_parse::maybe_new_parser_from_source_str;
1414
use rustc_query_impl::QueryCtxt;
1515
use rustc_query_system::query::print_query_stack;
@@ -154,12 +154,14 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
154154
Ok(meta_item) if parser.token == token::Eof => {
155155
if let Some(args) = meta_item.meta_item_list() {
156156
if meta_item.has_name(sym::names) {
157-
let names_valid =
158-
check_cfg.names_valid.get_or_insert_with(|| FxHashSet::default());
157+
check_cfg.exhaustive_names = true;
159158
for arg in args {
160159
if arg.is_word() && arg.ident().is_some() {
161160
let ident = arg.ident().expect("multi-segment cfg key");
162-
names_valid.insert(ident.name.to_string());
161+
check_cfg
162+
.expecteds
163+
.entry(ident.name.to_string())
164+
.or_insert(ExpectedValues::Any);
163165
} else {
164166
error!("`names()` arguments must be simple identifiers");
165167
}
@@ -168,8 +170,8 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
168170
if let Some((name, values)) = args.split_first() {
169171
if name.is_word() && name.ident().is_some() {
170172
let ident = name.ident().expect("multi-segment cfg key");
171-
let ident_values = check_cfg
172-
.values_valid
173+
let expected_values = check_cfg
174+
.expecteds
173175
.entry(ident.name.to_string())
174176
.or_insert_with(|| {
175177
ExpectedValues::Some(FxHashSet::default())
@@ -183,20 +185,24 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
183185
if let Some(LitKind::Str(s, _)) =
184186
val.lit().map(|lit| &lit.kind)
185187
{
186-
ident_values.insert(s.to_string());
188+
expected_values.insert(Some(s.to_string()));
187189
} else {
188190
error!(
189191
"`values()` arguments must be string literals"
190192
);
191193
}
192194
}
195+
196+
if values.is_empty() {
197+
expected_values.insert(None);
198+
}
193199
} else {
194200
error!(
195201
"`values()` first argument must be a simple identifier"
196202
);
197203
}
198204
} else if args.is_empty() {
199-
check_cfg.well_known_values = true;
205+
check_cfg.exhaustive_values = true;
200206
} else {
201207
expected_error();
202208
}
@@ -220,9 +226,6 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
220226
}
221227
}
222228

223-
if let Some(names_valid) = &mut check_cfg.names_valid {
224-
names_valid.extend(check_cfg.values_valid.keys().cloned());
225-
}
226229
check_cfg
227230
})
228231
}

compiler/rustc_lint/src/builtin.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOf};
6363
use rustc_middle::ty::print::with_no_trimmed_paths;
6464
use rustc_middle::ty::subst::GenericArgKind;
6565
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
66+
use rustc_session::config::ExpectedValues;
6667
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
6768
use rustc_span::edition::Edition;
6869
use rustc_span::source_map::Spanned;
@@ -3306,16 +3307,15 @@ impl EarlyLintPass for UnexpectedCfgs {
33063307
let cfg = &cx.sess().parse_sess.config;
33073308
let check_cfg = &cx.sess().parse_sess.check_config;
33083309
for &(name, value) in cfg {
3309-
if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
3310-
cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
3311-
name,
3312-
});
3313-
}
3314-
if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
3315-
cx.emit_lint(
3316-
UNEXPECTED_CFGS,
3317-
BuiltinUnexpectedCliConfigValue { name, value },
3318-
);
3310+
match check_cfg.expecteds.get(&name) {
3311+
Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
3312+
let value = value.unwrap_or(kw::Empty);
3313+
cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigValue { name, value });
3314+
}
3315+
None if check_cfg.exhaustive_names => {
3316+
cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { name });
3317+
}
3318+
_ => { /* expected */ }
33193319
}
33203320
}
33213321
}

compiler/rustc_lint/src/context.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -769,21 +769,23 @@ pub trait LintContext: Sized {
769769
db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
770770
},
771771
BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), None) => {
772-
let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
773-
bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
774-
};
775-
let possibilities: Vec<Symbol> = names_valid.iter().map(|s| *s).collect();
772+
let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect();
776773

777774
// Suggest the most probable if we found one
778775
if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
779776
db.span_suggestion(name_span, "did you mean", best_match, Applicability::MaybeIncorrect);
780777
}
781778
},
782779
BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
783-
let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
780+
let Some(rustc_session::config::ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else {
784781
bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
785782
};
786-
let possibilities: Vec<Symbol> = values.iter().map(|&s| s).collect();
783+
let mut have_none_possibility = false;
784+
let possibilities: Vec<Symbol> = values.iter()
785+
.inspect(|a| have_none_possibility |= a.is_none())
786+
.copied()
787+
.filter_map(std::convert::identity)
788+
.collect();
787789

788790
// Show the full list if all possible values for a given name, but don't do it
789791
// for names as the possibilities could be very long

0 commit comments

Comments
 (0)