Use rustc_safe_intrinsic attribute to check for intrinsic safety

Instead of maintaining a list that is poorly kept in sync we can just
use the attribute.
This commit is contained in:
Nilstrieb 2022-12-30 20:29:37 +01:00
parent 3033c3ddbf
commit 72afcf2cad
3 changed files with 14 additions and 48 deletions

View file

@ -350,6 +350,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(rustc_safe_intrinsic, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
gated!( gated!(
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
"allow_internal_unstable side-steps feature gating and stability checks", "allow_internal_unstable side-steps feature gating and stability checks",

View file

@ -17,7 +17,7 @@ use hir_def::{
ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
TypeOrConstParamId, TypeParamId, TypeOrConstParamId, TypeParamId,
}; };
use hir_expand::name::{known, Name}; use hir_expand::name::Name;
use itertools::Either; use itertools::Either;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -335,54 +335,18 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
// Function in an `extern` block are always unsafe to call, except when it has // Function in an `extern` block are always unsafe to call, except when it has
// `"rust-intrinsic"` ABI there are a few exceptions. // `"rust-intrinsic"` ABI there are a few exceptions.
let id = block.lookup(db.upcast()).id; let id = block.lookup(db.upcast()).id;
!matches!(
id.item_tree(db.upcast())[id.value].abi.as_deref(), let is_intrinsic =
Some("rust-intrinsic") if !is_intrinsic_fn_unsafe(&data.name) id.item_tree(db.upcast())[id.value].abi.as_deref() == Some("rust-intrinsic");
)
if is_intrinsic {
// Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
!data.attrs.by_key("rustc_safe_intrinsic").exists()
} else {
// Extern items are always unsafe
true
}
} }
_ => false, _ => 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)
}

View file

@ -86,6 +86,7 @@ fn main() {
check_diagnostics( check_diagnostics(
r#" r#"
extern "rust-intrinsic" { extern "rust-intrinsic" {
#[rustc_safe_intrinsic]
pub fn bitreverse(x: u32) -> u32; // Safe intrinsic pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
} }