6307: Add whitelist of safe intrinsics r=frazar a=frazar

This PR should fix #5996, where intrinsic operations where all marked as unsafe.

I'm rather new to this codebase, so I might be doing something *very* wrong. Please forgive me!

In particular, I'm not sure how to "check that we are in extern `rust-intrinsics`" as mentioned [in this comment](https://github.com/rust-analyzer/rust-analyzer/issues/5996#issuecomment-709234802). 

Co-authored-by: Francesco Zardi <frazar@users.noreply.github.com>
This commit is contained in:
bors[bot] 2020-10-21 20:09:11 +00:00 committed by GitHub
commit 9eb6cbb80b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 2 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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
}
"#,
);
}