mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 06:41:48 +00:00
Determine function unsafety semantically
This commit is contained in:
parent
12f803d1e3
commit
5d8b4c40eb
12 changed files with 107 additions and 98 deletions
|
@ -8,14 +8,16 @@ use hir_def::{
|
|||
DefWithBodyId,
|
||||
};
|
||||
|
||||
use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind};
|
||||
use crate::{
|
||||
db::HirDatabase, utils::is_fn_unsafe_to_call, InferenceResult, Interner, TyExt, TyKind,
|
||||
};
|
||||
|
||||
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
||||
let infer = db.infer(def);
|
||||
let mut res = Vec::new();
|
||||
|
||||
let is_unsafe = match def {
|
||||
DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
|
||||
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
|
||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
|
||||
};
|
||||
if is_unsafe {
|
||||
|
@ -62,7 +64,7 @@ fn walk_unsafe(
|
|||
match expr {
|
||||
&Expr::Call { callee, .. } => {
|
||||
if let Some(func) = infer[callee].as_fn_def(db) {
|
||||
if db.function_data(func).is_unsafe() {
|
||||
if is_fn_unsafe_to_call(db, func) {
|
||||
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +81,7 @@ fn walk_unsafe(
|
|||
Expr::MethodCall { .. } => {
|
||||
if infer
|
||||
.method_resolution(current)
|
||||
.map(|(func, _)| db.function_data(func).is_unsafe())
|
||||
.map(|(func, _)| is_fn_unsafe_to_call(db, func))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
|
|
|
@ -748,7 +748,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.infer_pat(*pat, &ty, BindingMode::default());
|
||||
}
|
||||
let error_ty = &TypeRef::Error;
|
||||
let return_ty = if data.is_async() {
|
||||
let return_ty = if data.has_async_kw() {
|
||||
data.async_ret_type.as_deref().unwrap_or(error_ty)
|
||||
} else {
|
||||
&*data.ret_type
|
||||
|
|
|
@ -64,7 +64,7 @@ pub use mapping::{
|
|||
to_placeholder_idx,
|
||||
};
|
||||
pub use traits::TraitEnvironment;
|
||||
pub use utils::all_super_traits;
|
||||
pub use utils::{all_super_traits, is_fn_unsafe_to_call};
|
||||
pub use walk::TypeWalk;
|
||||
|
||||
pub use chalk_ir::{
|
||||
|
|
|
@ -15,10 +15,10 @@ use hir_def::{
|
|||
path::Path,
|
||||
resolver::{HasResolver, TypeNs},
|
||||
type_ref::{TraitBoundModifier, TypeRef},
|
||||
ConstParamId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
|
||||
TypeParamId,
|
||||
ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
|
||||
TypeOrConstParamId, TypeParamId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use hir_expand::name::{known, name, Name};
|
||||
use itertools::Either;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
@ -375,3 +375,66 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
|
|||
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
|
||||
let data = db.function_data(func);
|
||||
if data.has_unsafe_kw() {
|
||||
return true;
|
||||
}
|
||||
|
||||
match func.lookup(db.upcast()).container {
|
||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||
// Function in an `extern` block are always unsafe to call, except when it has
|
||||
// `"rust-intrinsic"` ABI there are a few exceptions.
|
||||
let id = block.lookup(db.upcast()).id;
|
||||
match id.item_tree(db.upcast())[id.value].abi.as_deref() {
|
||||
Some("rust-intrinsic") => is_intrinsic_fn_unsafe(&data.name),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the given intrinsic is unsafe to call, or false otherwise.
|
||||
fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
|
||||
// Should be kept in sync with https://github.com/rust-lang/rust/blob/532d2b14c05f9bc20b2d27cbb5f4550d28343a36/compiler/rustc_typeck/src/check/intrinsic.rs#L72-L106
|
||||
![
|
||||
known::abort,
|
||||
known::add_with_overflow,
|
||||
known::bitreverse,
|
||||
known::black_box,
|
||||
known::bswap,
|
||||
known::caller_location,
|
||||
known::ctlz,
|
||||
known::ctpop,
|
||||
known::cttz,
|
||||
known::discriminant_value,
|
||||
known::forget,
|
||||
known::likely,
|
||||
known::maxnumf32,
|
||||
known::maxnumf64,
|
||||
known::min_align_of,
|
||||
known::minnumf32,
|
||||
known::minnumf64,
|
||||
known::mul_with_overflow,
|
||||
known::needs_drop,
|
||||
known::ptr_guaranteed_eq,
|
||||
known::ptr_guaranteed_ne,
|
||||
known::rotate_left,
|
||||
known::rotate_right,
|
||||
known::rustc_peek,
|
||||
known::saturating_add,
|
||||
known::saturating_sub,
|
||||
known::size_of,
|
||||
known::sub_with_overflow,
|
||||
known::type_id,
|
||||
known::type_name,
|
||||
known::unlikely,
|
||||
known::variant_count,
|
||||
known::wrapping_add,
|
||||
known::wrapping_mul,
|
||||
known::wrapping_sub,
|
||||
]
|
||||
.contains(name)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue