Skip to main content

hir_ty/
target_feature.rs

1//! Stuff for handling `#[target_feature]` (needed for unsafe check).
2
3use 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    /// Retrieves the target features from the attributes, and does not expand the target features implied by them.
44    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
50// List of the target features each target feature implies.
51// Ideally we'd depend on rustc for this, but rustc_target doesn't compile on stable,
52// and t-compiler prefers for it to stay this way.
53
54static 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            // Some target features appear in two archs, e.g. Arm and x86.
63            // Sometimes they contain different implications, e.g. `aes`.
64            // We should probably choose by the active arch, but for now just merge them.
65            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    });