Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/utils.rs')
-rw-r--r--crates/hir-ty/src/utils.rs44
1 files changed, 42 insertions, 2 deletions
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index bf7892f69b..ffd0b5b5e2 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -9,16 +9,18 @@ use chalk_ir::{
DebruijnIndex,
};
use hir_def::{
+ attr::Attrs,
db::DefDatabase,
generics::{WherePredicate, WherePredicateTypeTarget},
lang_item::LangItem,
resolver::{HasResolver, TypeNs},
+ tt,
type_ref::{TraitBoundModifier, TypeRef},
EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId,
TypeOrConstParamId,
};
use hir_expand::name::Name;
-use intern::sym;
+use intern::{sym, Symbol};
use rustc_abi::TargetDataLayout;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
@@ -264,12 +266,50 @@ impl<'a> ClosureSubst<'a> {
}
}
-pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
+#[derive(Debug, Default)]
+pub struct TargetFeatures {
+ enabled: FxHashSet<Symbol>,
+}
+
+impl TargetFeatures {
+ pub fn from_attrs(attrs: &Attrs) -> Self {
+ let enabled = attrs
+ .by_key(&sym::target_feature)
+ .tt_values()
+ .filter_map(|tt| {
+ match tt.token_trees().flat_tokens() {
+ [
+ tt::TokenTree::Leaf(tt::Leaf::Ident(enable_ident)),
+ tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. })),
+ tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { kind: tt::LitKind::Str, symbol: features, .. })),
+ ] if enable_ident.sym == sym::enable => Some(features),
+ _ => None,
+ }
+ })
+ .flat_map(|features| features.as_str().split(',').map(Symbol::intern))
+ .collect();
+ Self { enabled }
+ }
+}
+
+pub fn is_fn_unsafe_to_call(
+ db: &dyn HirDatabase,
+ func: FunctionId,
+ caller_target_features: &TargetFeatures,
+) -> bool {
let data = db.function_data(func);
if data.is_unsafe() {
return true;
}
+ if data.has_target_feature() {
+ // RFC 2396 <https://rust-lang.github.io/rfcs/2396-target-feature-1.1.html>.
+ let callee_target_features = TargetFeatures::from_attrs(&db.attrs(func.into()));
+ if !caller_target_features.enabled.is_superset(&callee_target_features.enabled) {
+ return true;
+ }
+ }
+
let loc = func.lookup(db.upcast());
match loc.container {
hir_def::ItemContainerId::ExternBlockId(block) => {