1use std::sync::LazyLock;
4use std::{borrow::Cow, ops::Deref};
5
6use hir_def::FunctionId;
7use hir_def::attrs::AttrFlags;
8use intern::Symbol;
9use rustc_hash::{FxHashMap, FxHashSet};
10
11use crate::db::HirDatabase;
12use generated::TARGET_FEATURE_IMPLICATIONS_RAW;
13
14mod generated;
15
16#[derive(Debug, Default, Clone)]
17pub struct TargetFeatures<'db> {
18 pub(crate) enabled: Cow<'db, FxHashSet<Symbol>>,
19}
20
21impl<'db> TargetFeatures<'db> {
22 pub fn from_fn(db: &'db dyn HirDatabase, owner: FunctionId) -> Self {
23 let mut result = TargetFeatures::from_fn_no_implications(db, owner);
24 result.expand_implications();
25 result
26 }
27
28 fn expand_implications(&mut self) {
29 let all_implications = LazyLock::force(&TARGET_FEATURE_IMPLICATIONS);
30 let enabled = self.enabled.to_mut();
31 let mut queue = enabled.iter().cloned().collect::<Vec<_>>();
32 while let Some(feature) = queue.pop() {
33 if let Some(implications) = all_implications.get(&feature) {
34 for implication in implications {
35 if enabled.insert(implication.clone()) {
36 queue.push(implication.clone());
37 }
38 }
39 }
40 }
41 }
42
43 pub(crate) fn from_fn_no_implications(db: &'db dyn HirDatabase, owner: FunctionId) -> Self {
45 let enabled = AttrFlags::target_features(db, owner);
46 Self { enabled: Cow::Borrowed(enabled) }
47 }
48}
49
50static TARGET_FEATURE_IMPLICATIONS: LazyLock<FxHashMap<Symbol, Box<[Symbol]>>> =
55 LazyLock::new(|| {
56 let mut result = FxHashMap::<Symbol, FxHashSet<Symbol>>::default();
57 for &(feature_str, ref _stability, implications) in
58 TARGET_FEATURE_IMPLICATIONS_RAW.iter().flat_map(Deref::deref)
59 {
60 let feature = Symbol::intern(feature_str);
61 let implications = implications.iter().copied().map(Symbol::intern);
62 result.entry(feature).or_default().extend(implications);
66 }
67 let mut result = result
68 .into_iter()
69 .map(|(feature, implications)| (feature, Box::from_iter(implications)))
70 .collect::<FxHashMap<_, _>>();
71 result.shrink_to_fit();
72 result
73 });