diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3328639cfe3..ca7fb4a43db 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}, @@ -555,7 +555,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) => { @@ -713,3 +714,45 @@ enum GenericsOwner<'a> { TypeAlias, Impl, } + +/// 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/c6e4db620a7d2f569f11dcab627430921ea8aacf/compiler/rustc_typeck/src/check/intrinsic.rs#L68 + ![ + known::abort, + known::min_align_of, + known::needs_drop, + known::caller_location, + known::size_of_val, + known::min_align_of_val, + known::add_with_overflow, + known::sub_with_overflow, + known::mul_with_overflow, + known::wrapping_add, + known::wrapping_sub, + known::wrapping_mul, + known::saturating_add, + known::saturating_sub, + known::rotate_left, + known::rotate_right, + known::ctpop, + known::ctlz, + known::cttz, + known::bswap, + known::bitreverse, + known::discriminant_value, + known::type_id, + known::likely, + known::unlikely, + known::ptr_guaranteed_eq, + known::ptr_guaranteed_ne, + known::minnumf32, + known::minnumf64, + known::maxnumf32, + known::rustc_peek, + known::maxnumf64, + known::type_name, + known::variant_count, + ] + .contains(&name) +} diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 63f8287079d..b26ffa1ef2e 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs @@ -208,6 +208,42 @@ pub mod known { PartialOrd, Eq, PartialEq, + // Safe intrinsics + abort, + size_of, + min_align_of, + needs_drop, + caller_location, + size_of_val, + min_align_of_val, + add_with_overflow, + sub_with_overflow, + mul_with_overflow, + wrapping_add, + wrapping_sub, + wrapping_mul, + saturating_add, + saturating_sub, + rotate_left, + rotate_right, + ctpop, + ctlz, + cttz, + bswap, + bitreverse, + discriminant_value, + type_id, + likely, + unlikely, + ptr_guaranteed_eq, + ptr_guaranteed_ne, + minnumf32, + minnumf64, + maxnumf32, + rustc_peek, + maxnumf64, + type_name, + variant_count, ); // self/Self cannot be used as an identifier diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index 21a121aad7e..2da9688cab0 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs @@ -199,6 +199,24 @@ fn main() { let x = STATIC_MUT.a; } } +"#, + ); + } + + #[test] + fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { + check_diagnostics( + r#" +extern "rust-intrinsic" { + pub fn bitreverse(x: u32) -> u32; // Safe intrinsic + pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic +} + +fn main() { + let _ = bitreverse(12); + let _ = floorf32(12.0); + //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block +} "#, ); }