1
Fork 0

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.
This commit is contained in:
Urgau 2023-04-30 14:43:59 +02:00
parent ad6f4b73eb
commit d327d5b168
5 changed files with 173 additions and 153 deletions

View file

@ -1056,37 +1056,76 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig
/// The parsed `--check-cfg` options
pub struct CheckCfg<T = String> {
/// The set of all `names()`, if None no name checking is performed
pub names_valid: Option<FxHashSet<T>>,
/// Is well known names activated
pub exhaustive_names: bool,
/// Is well known values activated
pub well_known_values: bool,
/// The set of all `values()`
pub values_valid: FxHashMap<T, FxHashSet<T>>,
pub exhaustive_values: bool,
/// All the expected values for a config name
pub expecteds: FxHashMap<T, ExpectedValues<T>>,
}
impl<T> Default for CheckCfg<T> {
fn default() -> Self {
CheckCfg {
names_valid: Default::default(),
values_valid: Default::default(),
well_known_values: false,
exhaustive_names: false,
exhaustive_values: false,
expecteds: FxHashMap::default(),
}
}
}
impl<T> CheckCfg<T> {
fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> {
CheckCfg {
names_valid: self
.names_valid
.as_ref()
.map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
values_valid: self
.values_valid
.iter()
.map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
exhaustive_names: self.exhaustive_names,
exhaustive_values: self.exhaustive_values,
expecteds: self
.expecteds
.into_iter()
.map(|(name, values)| {
(
f(name),
match values {
ExpectedValues::Some(values) => ExpectedValues::Some(
values.into_iter().map(|b| b.map(|b| f(b))).collect(),
),
ExpectedValues::Any => ExpectedValues::Any,
},
)
})
.collect(),
well_known_values: self.well_known_values,
}
}
}
pub enum ExpectedValues<T> {
Some(FxHashSet<Option<T>>),
Any,
}
impl<T: Eq + Hash> ExpectedValues<T> {
fn insert(&mut self, value: T) -> bool {
match self {
ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)),
ExpectedValues::Any => false,
}
}
}
impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
match self {
ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)),
ExpectedValues::Any => {}
}
}
}
impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
match self {
ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))),
ExpectedValues::Any => {}
}
}
}
@ -1095,58 +1134,27 @@ impl<T> CheckCfg<T> {
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
/// but the symbol interner is not yet set up then, so we must convert it later.
pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
cfg.map_data(|s| Symbol::intern(s))
cfg.map_data(|s| Symbol::intern(&s))
}
impl CrateCheckConfig {
/// Fills a `CrateCheckConfig` with well-known configuration names.
fn fill_well_known_names(&mut self) {
// NOTE: This should be kept in sync with `default_configuration` and
// `fill_well_known_values`
const WELL_KNOWN_NAMES: &[Symbol] = &[
// rustc
sym::unix,
sym::windows,
sym::target_os,
sym::target_family,
sym::target_arch,
sym::target_endian,
sym::target_pointer_width,
sym::target_env,
sym::target_abi,
sym::target_vendor,
sym::target_thread_local,
sym::target_has_atomic_load_store,
sym::target_has_atomic,
sym::target_has_atomic_equal_alignment,
sym::target_feature,
sym::panic,
sym::sanitize,
sym::debug_assertions,
sym::proc_macro,
sym::test,
sym::feature,
// rustdoc
sym::doc,
sym::doctest,
// miri
sym::miri,
];
// We only insert well-known names if `names()` was activated
if let Some(names_valid) = &mut self.names_valid {
names_valid.extend(WELL_KNOWN_NAMES);
}
}
/// Fills a `CrateCheckConfig` with well-known configuration values.
fn fill_well_known_values(&mut self, current_target: &Target) {
if !self.well_known_values {
pub fn fill_well_known(&mut self, current_target: &Target) {
if !self.exhaustive_values && !self.exhaustive_names {
return;
}
// NOTE: This should be kept in sync with `default_configuration` and
// `fill_well_known_names`
let no_values = || {
let mut values = FxHashSet::default();
values.insert(None);
ExpectedValues::Some(values)
};
let empty_values = || {
let values = FxHashSet::default();
ExpectedValues::Some(values)
};
// NOTE: This should be kept in sync with `default_configuration`
let panic_values = &PanicStrategy::all();
@ -1166,6 +1174,9 @@ impl CrateCheckConfig {
// Unknown possible values:
// - `feature`
// - `target_feature`
for name in [sym::feature, sym::target_feature] {
self.expecteds.entry(name).or_insert(ExpectedValues::Any);
}
// No-values
for name in [
@ -1179,20 +1190,23 @@ impl CrateCheckConfig {
sym::debug_assertions,
sym::target_thread_local,
] {
self.values_valid.entry(name).or_default();
self.expecteds.entry(name).or_insert_with(no_values);
}
// Pre-defined values
self.values_valid.entry(sym::panic).or_default().extend(panic_values);
self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
self.values_valid
.entry(sym::target_has_atomic_load_store)
.or_default()
self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values);
self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values);
self.expecteds
.entry(sym::target_has_atomic)
.or_insert_with(no_values)
.extend(atomic_values);
self.values_valid
self.expecteds
.entry(sym::target_has_atomic_load_store)
.or_insert_with(no_values)
.extend(atomic_values);
self.expecteds
.entry(sym::target_has_atomic_equal_alignment)
.or_default()
.or_insert_with(no_values)
.extend(atomic_values);
// Target specific values
@ -1210,47 +1224,50 @@ impl CrateCheckConfig {
// Initialize (if not already initialized)
for &e in VALUES {
self.values_valid.entry(e).or_default();
let entry = self.expecteds.entry(e);
if !self.exhaustive_values {
entry.or_insert(ExpectedValues::Any);
} else {
entry.or_insert_with(empty_values);
}
}
// Get all values map at once otherwise it would be costly.
// (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
let [
values_target_os,
values_target_family,
values_target_arch,
values_target_endian,
values_target_env,
values_target_abi,
values_target_vendor,
values_target_pointer_width,
] = self
.values_valid
.get_many_mut(VALUES)
.expect("unable to get all the check-cfg values buckets");
if self.exhaustive_values {
// Get all values map at once otherwise it would be costly.
// (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
let [
values_target_os,
values_target_family,
values_target_arch,
values_target_endian,
values_target_env,
values_target_abi,
values_target_vendor,
values_target_pointer_width,
] = self
.expecteds
.get_many_mut(VALUES)
.expect("unable to get all the check-cfg values buckets");
for target in TARGETS
.iter()
.map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
.chain(iter::once(current_target.clone()))
{
values_target_os.insert(Symbol::intern(&target.options.os));
values_target_family
.extend(target.options.families.iter().map(|family| Symbol::intern(family)));
values_target_arch.insert(Symbol::intern(&target.arch));
values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
values_target_env.insert(Symbol::intern(&target.options.env));
values_target_abi.insert(Symbol::intern(&target.options.abi));
values_target_vendor.insert(Symbol::intern(&target.options.vendor));
values_target_pointer_width.insert(sym::integer(target.pointer_width));
for target in TARGETS
.iter()
.map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
.chain(iter::once(current_target.clone()))
{
values_target_os.insert(Symbol::intern(&target.options.os));
values_target_family.extend(
target.options.families.iter().map(|family| Symbol::intern(family)),
);
values_target_arch.insert(Symbol::intern(&target.arch));
values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
values_target_env.insert(Symbol::intern(&target.options.env));
values_target_abi.insert(Symbol::intern(&target.options.abi));
values_target_vendor.insert(Symbol::intern(&target.options.vendor));
values_target_pointer_width.insert(sym::integer(target.pointer_width));
}
}
}
}
pub fn fill_well_known(&mut self, current_target: &Target) {
self.fill_well_known_names();
self.fill_well_known_values(current_target);
}
}
pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {