fix: Handle newstyle rustc_intrinsic safety correctly

This commit is contained in:
Lukas Wirth 2025-01-06 09:20:03 +01:00
parent 6725e046df
commit e462ee79e4
2 changed files with 24 additions and 9 deletions

View file

@ -270,17 +270,15 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
return true; return true;
} }
let is_intrinsic = db.attrs(func.into()).by_key(&sym::rustc_intrinsic).exists()
|| data.abi.as_ref() == Some(&sym::rust_dash_intrinsic);
let loc = func.lookup(db.upcast()); let loc = func.lookup(db.upcast());
match loc.container { match loc.container {
hir_def::ItemContainerId::ExternBlockId(block) => { hir_def::ItemContainerId::ExternBlockId(block) => {
if is_intrinsic || { let id = block.lookup(db.upcast()).id;
let id = block.lookup(db.upcast()).id; let is_intrinsic_block =
id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic) id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
} { if is_intrinsic_block {
// Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute // legacy intrinsics
// extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
!db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists()
} else { } else {
// Function in an `extern` block are always unsafe to call, except when // Function in an `extern` block are always unsafe to call, except when
@ -288,7 +286,6 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
!data.is_safe() !data.is_safe()
} }
} }
_ if is_intrinsic => !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists(),
_ => false, _ => false,
} }
} }

View file

@ -237,6 +237,24 @@ fn main() {
fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
check_diagnostics( check_diagnostics(
r#" r#"
#[rustc_intrinsic]
pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
#[rustc_intrinsic]
pub unsafe fn floorf32(x: f32) -> f32; // Unsafe intrinsic
fn main() {
let _ = bitreverse(12);
let _ = floorf32(12.0);
//^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
}
"#,
);
}
#[test]
fn no_missing_unsafe_diagnostic_with_legacy_safe_intrinsic() {
check_diagnostics(
r#"
extern "rust-intrinsic" { extern "rust-intrinsic" {
#[rustc_safe_intrinsic] #[rustc_safe_intrinsic]
pub fn bitreverse(x: u32) -> u32; // Safe intrinsic pub fn bitreverse(x: u32) -> u32; // Safe intrinsic