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.rs | 44 |
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) => { |