Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b5e463d

Browse files
committedMar 9, 2024
Add cache-based fast path for cfgs and check-cfgs
1 parent aa029ce commit b5e463d

File tree

3 files changed

+78
-32
lines changed

3 files changed

+78
-32
lines changed
 

‎compiler/rustc_attr/src/builtin.rs

+33-31
Original file line numberDiff line numberDiff line change
@@ -525,38 +525,40 @@ pub fn cfg_matches(
525525
) -> bool {
526526
eval_condition(cfg, sess, features, &mut |cfg| {
527527
try_gate_cfg(cfg.name, cfg.span, sess, features);
528-
match sess.psess.check_config.expecteds.get(&cfg.name) {
529-
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
530-
sess.psess.buffer_lint_with_diagnostic(
531-
UNEXPECTED_CFGS,
532-
cfg.span,
533-
lint_node_id,
534-
if let Some(value) = cfg.value {
535-
format!("unexpected `cfg` condition value: `{value}`")
536-
} else {
537-
format!("unexpected `cfg` condition value: (none)")
538-
},
539-
BuiltinLintDiag::UnexpectedCfgValue(
540-
(cfg.name, cfg.name_span),
541-
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
542-
),
543-
);
544-
}
545-
None if sess.psess.check_config.exhaustive_names => {
546-
sess.psess.buffer_lint_with_diagnostic(
547-
UNEXPECTED_CFGS,
548-
cfg.span,
549-
lint_node_id,
550-
format!("unexpected `cfg` condition name: `{}`", cfg.name),
551-
BuiltinLintDiag::UnexpectedCfgName(
552-
(cfg.name, cfg.name_span),
553-
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
554-
),
555-
);
528+
sess.psess.config_cache.get(&(cfg.name, cfg.value)).copied().unwrap_or_else(|| {
529+
match sess.psess.check_config.expecteds.get(&cfg.name) {
530+
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
531+
sess.psess.buffer_lint_with_diagnostic(
532+
UNEXPECTED_CFGS,
533+
cfg.span,
534+
lint_node_id,
535+
if let Some(value) = cfg.value {
536+
format!("unexpected `cfg` condition value: `{value}`")
537+
} else {
538+
format!("unexpected `cfg` condition value: (none)")
539+
},
540+
BuiltinLintDiag::UnexpectedCfgValue(
541+
(cfg.name, cfg.name_span),
542+
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
543+
),
544+
);
545+
}
546+
None if sess.psess.check_config.exhaustive_names => {
547+
sess.psess.buffer_lint_with_diagnostic(
548+
UNEXPECTED_CFGS,
549+
cfg.span,
550+
lint_node_id,
551+
format!("unexpected `cfg` condition name: `{}`", cfg.name),
552+
BuiltinLintDiag::UnexpectedCfgName(
553+
(cfg.name, cfg.name_span),
554+
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
555+
),
556+
);
557+
}
558+
_ => { /* not unexpected */ }
556559
}
557-
_ => { /* not unexpected */ }
558-
}
559-
sess.psess.config.contains(&(cfg.name, cfg.value))
560+
sess.psess.config.contains(&(cfg.name, cfg.value))
561+
})
560562
})
561563
}
562564

‎compiler/rustc_interface/src/interface.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_query_impl::QueryCtxt;
1717
use rustc_query_system::query::print_query_stack;
1818
use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
1919
use rustc_session::filesearch::sysroot_candidates;
20-
use rustc_session::parse::ParseSess;
20+
use rustc_session::parse::{CfgCache, ParseSess};
2121
use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session};
2222
use rustc_span::source_map::FileLoader;
2323
use rustc_span::symbol::sym;
@@ -260,6 +260,35 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
260260
check_cfg
261261
}
262262

263+
/// Create the config cache of `--cfg` and `--check-cfg` for internal use.
264+
///
265+
/// The cache is used to reduce the number of hashmap lookups by
266+
/// pre-computing the maximum possible configs[^1] from `--check-cfg` and `--cfg`.
267+
///
268+
/// It heavily favours expected cfgs (if any are provided), since if the
269+
/// user provides a list of expected cfgs, they are likely to care more
270+
/// about expected cfgs than unexpected cfgs.
271+
///
272+
/// [^1]: See [`CfgCache`] for an explanation of "maximum possible".
273+
fn config_cache(config: &Cfg, check_cfg: &CheckCfg) -> CfgCache {
274+
let mut config_cache = CfgCache::default();
275+
276+
if check_cfg.expecteds.is_empty() {
277+
config_cache.extend(config.iter().map(|cfg| (*cfg, true)));
278+
} else {
279+
#[allow(rustc::potential_query_instability)]
280+
for (name, expected) in &check_cfg.expecteds {
281+
if let ExpectedValues::Some(values) = expected {
282+
config_cache.extend(
283+
values.iter().map(|value| ((*name, *value), config.contains(&(*name, *value)))),
284+
);
285+
}
286+
}
287+
}
288+
289+
config_cache
290+
}
291+
263292
/// The compiler configuration
264293
pub struct Config {
265294
/// Command line options
@@ -402,6 +431,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
402431
check_cfg.fill_well_known(&sess.target);
403432
sess.psess.check_config = check_cfg;
404433

434+
sess.psess.config_cache = config_cache(&sess.psess.config, &sess.psess.check_config);
435+
405436
if let Some(psess_created) = config.psess_created {
406437
psess_created(&mut sess.psess);
407438
}

‎compiler/rustc_session/src/parse.rs

+13
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,24 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
196196
}
197197
}
198198

199+
/// Config cache that tries to combine expected cfgs and enabled cfgs.
200+
///
201+
/// If a config is found, this means it is definitely an expected config
202+
/// and the value represents whenever that config is enabled.
203+
///
204+
/// If a config is not found, it doesn't imply anything! The config still may
205+
/// be enabled and it may also be expected. You should only rely on the
206+
/// cache having a config and not "NOT having it". You should always fallback
207+
/// to a manual lookup in `ParseSess::config` and `ParseSess::check_cfg`.
208+
pub type CfgCache = FxHashMap<(Symbol, Option<Symbol>), bool>;
209+
199210
/// Info about a parsing session.
200211
pub struct ParseSess {
201212
pub dcx: DiagCtxt,
202213
pub unstable_features: UnstableFeatures,
203214
pub config: Cfg,
204215
pub check_config: CheckCfg,
216+
pub config_cache: CfgCache,
205217
pub edition: Edition,
206218
/// Places where raw identifiers were used. This is used to avoid complaining about idents
207219
/// clashing with keywords in new editions.
@@ -250,6 +262,7 @@ impl ParseSess {
250262
unstable_features: UnstableFeatures::from_environment(None),
251263
config: Cfg::default(),
252264
check_config: CheckCfg::default(),
265+
config_cache: CfgCache::default(),
253266
edition: ExpnId::root().expn_data().edition,
254267
raw_identifier_spans: Default::default(),
255268
bad_unicode_identifiers: Lock::new(Default::default()),

0 commit comments

Comments
 (0)
Please sign in to comment.