From a9d996a7c5f962b4ac914c86f5005eb22128f511 Mon Sep 17 00:00:00 2001 From: Francesco Zardi Date: Wed, 21 Oct 2020 09:06:05 +0200 Subject: Add whitelist of safe intrinsics --- crates/hir_def/src/item_tree/lower.rs | 44 +++++++++++++++++++++++++++++++++-- crates/hir_def/src/item_tree/tests.rs | 20 ++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) (limited to 'crates/hir_def/src') diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3328639cf..1a29081c5 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -3,7 +3,7 @@ use std::{collections::hash_map::Entry, mem, sync::Arc}; use arena::map::ArenaMap; -use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; +use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; use smallvec::SmallVec; use syntax::{ ast::{self, ModuleItemOwner}, @@ -42,6 +42,45 @@ pub(super) struct Ctx { forced_visibility: Option, } +/// Returns `true` if the given intrinsic is unsafe to call or not. +pub fn is_intrinsic_fn_unsafe(name: &Name) -> bool { + // Should be kept in sync with https://github.com/rust-lang/rust/blob/c6e4db620a7d2f569f11dcab627430921ea8aacf/compiler/rustc_typeck/src/check/intrinsic.rs#L68 + *name != known::abort + && *name != known::min_align_of + && *name != known::needs_drop + && *name != known::caller_location + && *name != known::size_of_val + && *name != known::min_align_of_val + && *name != known::add_with_overflow + && *name != known::sub_with_overflow + && *name != known::mul_with_overflow + && *name != known::wrapping_add + && *name != known::wrapping_sub + && *name != known::wrapping_mul + && *name != known::saturating_add + && *name != known::saturating_sub + && *name != known::rotate_left + && *name != known::rotate_right + && *name != known::ctpop + && *name != known::ctlz + && *name != known::cttz + && *name != known::bswap + && *name != known::bitreverse + && *name != known::discriminant_value + && *name != known::type_id + && *name != known::likely + && *name != known::unlikely + && *name != known::ptr_guaranteed_eq + && *name != known::ptr_guaranteed_ne + && *name != known::minnumf32 + && *name != known::minnumf64 + && *name != known::maxnumf32 + && *name != known::rustc_peek + && *name != known::maxnumf64 + && *name != known::type_name + && *name != known::variant_count +} + impl Ctx { pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { Self { @@ -555,7 +594,8 @@ impl Ctx { let id: ModItem = match item { ast::ExternItem::Fn(ast) => { let func = self.lower_function(&ast)?; - self.data().functions[func.index].is_unsafe = true; + self.data().functions[func.index].is_unsafe = + is_intrinsic_fn_unsafe(&self.data().functions[func.index].name); func.into() } ast::ExternItem::Static(ast) => { diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index 4b354c4c1..495c5a7e9 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs @@ -437,3 +437,23 @@ fn assoc_item_macros() { "#]], ); } + +#[test] +fn safe_intrinsic() { + check( + r" + #![feature(core_intrinsics)] + + fn reverse(input: u32) -> u32 { + std::intrinsics::bitreverse(input) + } + ", + expect![[r#" + inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("feature"))] }, input: Some(TokenTree(SUBTREE () 0 + IDENT core_intrinsics 1)) }]) } + + top-level items: + Function { name: Name(Text("reverse")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, has_body: true, is_unsafe: false, params: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u32"))] }, generic_args: [None] })], is_varargs: false, ret_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u32"))] }, generic_args: [None] }), ast_id: FileAstId::(0) } + "#]], + ); +} -- cgit v1.2.3