Skip to content

Commit ec871bb

Browse files
bors[bot]Jonas Schievink
and
Jonas Schievink
authored
Merge #11930
11930: internal: move function unsafety determination out of the ItemTree r=jonas-schievink a=jonas-schievink Resolves some FIXMEs. I've also renamed some FnFlags to be more explicit about what they represent (presence of keywords, not necessarily presence of semantics) bors r+ Co-authored-by: Jonas Schievink <[email protected]>
2 parents 12f803d + 5d8b4c4 commit ec871bb

File tree

12 files changed

+107
-98
lines changed

12 files changed

+107
-98
lines changed

crates/hir/src/display.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ impl HirDisplay for Function {
2626
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
2727
let data = f.db.function_data(self.id);
2828
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
29-
if data.is_default() {
29+
if data.has_default_kw() {
3030
f.write_str("default ")?;
3131
}
32-
if data.is_const() {
32+
if data.has_const_kw() {
3333
f.write_str("const ")?;
3434
}
35-
if data.is_async() {
35+
if data.has_async_kw() {
3636
f.write_str("async ")?;
3737
}
38-
if data.is_unsafe() {
38+
if self.is_unsafe_to_call(f.db) {
3939
f.write_str("unsafe ")?;
4040
}
4141
if let Some(abi) = &data.abi {
@@ -96,7 +96,7 @@ impl HirDisplay for Function {
9696
// `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
9797
// Use ugly pattern match to strip the Future trait.
9898
// Better way?
99-
let ret_type = if !data.is_async() {
99+
let ret_type = if !data.has_async_kw() {
100100
&data.ret_type
101101
} else {
102102
match &*data.ret_type {

crates/hir/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,16 +1421,16 @@ impl Function {
14211421
.collect()
14221422
}
14231423

1424-
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
1425-
db.function_data(self.id).is_unsafe()
1426-
}
1427-
14281424
pub fn is_const(self, db: &dyn HirDatabase) -> bool {
1429-
db.function_data(self.id).is_const()
1425+
db.function_data(self.id).has_const_kw()
14301426
}
14311427

14321428
pub fn is_async(self, db: &dyn HirDatabase) -> bool {
1433-
db.function_data(self.id).is_async()
1429+
db.function_data(self.id).has_async_kw()
1430+
}
1431+
1432+
pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
1433+
hir_ty::is_fn_unsafe_to_call(db, self.id)
14341434
}
14351435

14361436
/// Whether this function declaration has a definition.

crates/hir_def/src/data.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,20 +110,20 @@ impl FunctionData {
110110
self.flags.contains(FnFlags::HAS_SELF_PARAM)
111111
}
112112

113-
pub fn is_default(&self) -> bool {
114-
self.flags.contains(FnFlags::IS_DEFAULT)
113+
pub fn has_default_kw(&self) -> bool {
114+
self.flags.contains(FnFlags::HAS_DEFAULT_KW)
115115
}
116116

117-
pub fn is_const(&self) -> bool {
118-
self.flags.contains(FnFlags::IS_CONST)
117+
pub fn has_const_kw(&self) -> bool {
118+
self.flags.contains(FnFlags::HAS_CONST_KW)
119119
}
120120

121-
pub fn is_async(&self) -> bool {
122-
self.flags.contains(FnFlags::IS_ASYNC)
121+
pub fn has_async_kw(&self) -> bool {
122+
self.flags.contains(FnFlags::HAS_ASYNC_KW)
123123
}
124124

125-
pub fn is_unsafe(&self) -> bool {
126-
self.flags.contains(FnFlags::IS_UNSAFE)
125+
pub fn has_unsafe_kw(&self) -> bool {
126+
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
127127
}
128128

129129
pub fn is_varargs(&self) -> bool {

crates/hir_def/src/item_tree.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -606,10 +606,10 @@ bitflags::bitflags! {
606606
pub(crate) struct FnFlags: u8 {
607607
const HAS_SELF_PARAM = 1 << 0;
608608
const HAS_BODY = 1 << 1;
609-
const IS_DEFAULT = 1 << 2;
610-
const IS_CONST = 1 << 3;
611-
const IS_ASYNC = 1 << 4;
612-
const IS_UNSAFE = 1 << 5;
609+
const HAS_DEFAULT_KW = 1 << 2;
610+
const HAS_CONST_KW = 1 << 3;
611+
const HAS_ASYNC_KW = 1 << 4;
612+
const HAS_UNSAFE_KW = 1 << 5;
613613
const IS_VARARGS = 1 << 6;
614614
}
615615
}

crates/hir_def/src/item_tree/lower.rs

Lines changed: 7 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::{collections::hash_map::Entry, mem, sync::Arc};
44

5-
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
5+
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
66
use syntax::ast::{self, HasModuleItem};
77

88
use crate::{
@@ -343,16 +343,16 @@ impl<'a> Ctx<'a> {
343343
flags |= FnFlags::HAS_SELF_PARAM;
344344
}
345345
if func.default_token().is_some() {
346-
flags |= FnFlags::IS_DEFAULT;
346+
flags |= FnFlags::HAS_DEFAULT_KW;
347347
}
348348
if func.const_token().is_some() {
349-
flags |= FnFlags::IS_CONST;
349+
flags |= FnFlags::HAS_CONST_KW;
350350
}
351351
if func.async_token().is_some() {
352-
flags |= FnFlags::IS_ASYNC;
352+
flags |= FnFlags::HAS_ASYNC_KW;
353353
}
354354
if func.unsafe_token().is_some() {
355-
flags |= FnFlags::IS_UNSAFE;
355+
flags |= FnFlags::HAS_UNSAFE_KW;
356356
}
357357

358358
let mut res = Function {
@@ -554,22 +554,10 @@ impl<'a> Ctx<'a> {
554554
// should be considered to be in an extern block too.
555555
let attrs = RawAttrs::new(self.db, &item, self.hygiene());
556556
let id: ModItem = match item {
557-
ast::ExternItem::Fn(ast) => {
558-
let func_id = self.lower_function(&ast)?;
559-
let func = &mut self.data().functions[func_id.index];
560-
if is_intrinsic_fn_unsafe(&func.name) {
561-
// FIXME: this breaks in macros
562-
func.flags |= FnFlags::IS_UNSAFE;
563-
}
564-
func_id.into()
565-
}
557+
ast::ExternItem::Fn(ast) => self.lower_function(&ast)?.into(),
566558
ast::ExternItem::Static(ast) => self.lower_static(&ast)?.into(),
567559
ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(&ty)?.into(),
568-
ast::ExternItem::MacroCall(call) => {
569-
// FIXME: we need some way of tracking that the macro call is in an
570-
// extern block
571-
self.lower_macro_call(&call)?.into()
572-
}
560+
ast::ExternItem::MacroCall(call) => self.lower_macro_call(&call)?.into(),
573561
};
574562
self.add_attrs(id.into(), attrs);
575563
Some(id)
@@ -716,49 +704,6 @@ enum GenericsOwner<'a> {
716704
Impl,
717705
}
718706

719-
/// Returns `true` if the given intrinsic is unsafe to call, or false otherwise.
720-
fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
721-
// Should be kept in sync with https://github.com/rust-lang/rust/blob/532d2b14c05f9bc20b2d27cbb5f4550d28343a36/compiler/rustc_typeck/src/check/intrinsic.rs#L72-L106
722-
![
723-
known::abort,
724-
known::add_with_overflow,
725-
known::bitreverse,
726-
known::black_box,
727-
known::bswap,
728-
known::caller_location,
729-
known::ctlz,
730-
known::ctpop,
731-
known::cttz,
732-
known::discriminant_value,
733-
known::forget,
734-
known::likely,
735-
known::maxnumf32,
736-
known::maxnumf64,
737-
known::min_align_of,
738-
known::minnumf32,
739-
known::minnumf64,
740-
known::mul_with_overflow,
741-
known::needs_drop,
742-
known::ptr_guaranteed_eq,
743-
known::ptr_guaranteed_ne,
744-
known::rotate_left,
745-
known::rotate_right,
746-
known::rustc_peek,
747-
known::saturating_add,
748-
known::saturating_sub,
749-
known::size_of,
750-
known::sub_with_overflow,
751-
known::type_id,
752-
known::type_name,
753-
known::unlikely,
754-
known::variant_count,
755-
known::wrapping_add,
756-
known::wrapping_mul,
757-
known::wrapping_sub,
758-
]
759-
.contains(name)
760-
}
761-
762707
fn lower_abi(abi: ast::Abi) -> Interned<str> {
763708
// FIXME: Abi::abi() -> Option<SyntaxToken>?
764709
match abi.syntax().last_token() {

crates/hir_def/src/item_tree/tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ extern "C" {
7676
pub(self) static EX_STATIC: u8 = _;
7777
7878
#[on_extern_fn] // AttrId { ast_index: 0 }
79-
// flags = 0x20
8079
pub(self) fn ex_fn() -> ();
8180
}
8281
"##]],

crates/hir_ty/src/diagnostics/unsafe_check.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ use hir_def::{
88
DefWithBodyId,
99
};
1010

11-
use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind};
11+
use crate::{
12+
db::HirDatabase, utils::is_fn_unsafe_to_call, InferenceResult, Interner, TyExt, TyKind,
13+
};
1214

1315
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
1416
let infer = db.infer(def);
1517
let mut res = Vec::new();
1618

1719
let is_unsafe = match def {
18-
DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
20+
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
1921
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
2022
};
2123
if is_unsafe {
@@ -62,7 +64,7 @@ fn walk_unsafe(
6264
match expr {
6365
&Expr::Call { callee, .. } => {
6466
if let Some(func) = infer[callee].as_fn_def(db) {
65-
if db.function_data(func).is_unsafe() {
67+
if is_fn_unsafe_to_call(db, func) {
6668
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
6769
}
6870
}
@@ -79,7 +81,7 @@ fn walk_unsafe(
7981
Expr::MethodCall { .. } => {
8082
if infer
8183
.method_resolution(current)
82-
.map(|(func, _)| db.function_data(func).is_unsafe())
84+
.map(|(func, _)| is_fn_unsafe_to_call(db, func))
8385
.unwrap_or(false)
8486
{
8587
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });

crates/hir_ty/src/infer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ impl<'a> InferenceContext<'a> {
748748
self.infer_pat(*pat, &ty, BindingMode::default());
749749
}
750750
let error_ty = &TypeRef::Error;
751-
let return_ty = if data.is_async() {
751+
let return_ty = if data.has_async_kw() {
752752
data.async_ret_type.as_deref().unwrap_or(error_ty)
753753
} else {
754754
&*data.ret_type

crates/hir_ty/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub use mapping::{
6464
to_placeholder_idx,
6565
};
6666
pub use traits::TraitEnvironment;
67-
pub use utils::all_super_traits;
67+
pub use utils::{all_super_traits, is_fn_unsafe_to_call};
6868
pub use walk::TypeWalk;
6969

7070
pub use chalk_ir::{

crates/hir_ty/src/utils.rs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ use hir_def::{
1515
path::Path,
1616
resolver::{HasResolver, TypeNs},
1717
type_ref::{TraitBoundModifier, TypeRef},
18-
ConstParamId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
19-
TypeParamId,
18+
ConstParamId, FunctionId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId,
19+
TypeOrConstParamId, TypeParamId,
2020
};
21-
use hir_expand::name::{name, Name};
21+
use hir_expand::name::{known, name, Name};
2222
use itertools::Either;
2323
use rustc_hash::FxHashSet;
2424
use smallvec::{smallvec, SmallVec};
@@ -375,3 +375,66 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
375375
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
376376
}
377377
}
378+
379+
pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
380+
let data = db.function_data(func);
381+
if data.has_unsafe_kw() {
382+
return true;
383+
}
384+
385+
match func.lookup(db.upcast()).container {
386+
hir_def::ItemContainerId::ExternBlockId(block) => {
387+
// Function in an `extern` block are always unsafe to call, except when it has
388+
// `"rust-intrinsic"` ABI there are a few exceptions.
389+
let id = block.lookup(db.upcast()).id;
390+
match id.item_tree(db.upcast())[id.value].abi.as_deref() {
391+
Some("rust-intrinsic") => is_intrinsic_fn_unsafe(&data.name),
392+
_ => true,
393+
}
394+
}
395+
_ => false,
396+
}
397+
}
398+
399+
/// Returns `true` if the given intrinsic is unsafe to call, or false otherwise.
400+
fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
401+
// Should be kept in sync with https://github.com/rust-lang/rust/blob/532d2b14c05f9bc20b2d27cbb5f4550d28343a36/compiler/rustc_typeck/src/check/intrinsic.rs#L72-L106
402+
![
403+
known::abort,
404+
known::add_with_overflow,
405+
known::bitreverse,
406+
known::black_box,
407+
known::bswap,
408+
known::caller_location,
409+
known::ctlz,
410+
known::ctpop,
411+
known::cttz,
412+
known::discriminant_value,
413+
known::forget,
414+
known::likely,
415+
known::maxnumf32,
416+
known::maxnumf64,
417+
known::min_align_of,
418+
known::minnumf32,
419+
known::minnumf64,
420+
known::mul_with_overflow,
421+
known::needs_drop,
422+
known::ptr_guaranteed_eq,
423+
known::ptr_guaranteed_ne,
424+
known::rotate_left,
425+
known::rotate_right,
426+
known::rustc_peek,
427+
known::saturating_add,
428+
known::saturating_sub,
429+
known::size_of,
430+
known::sub_with_overflow,
431+
known::type_id,
432+
known::type_name,
433+
known::unlikely,
434+
known::variant_count,
435+
known::wrapping_add,
436+
known::wrapping_mul,
437+
known::wrapping_sub,
438+
]
439+
.contains(name)
440+
}

crates/ide/src/syntax_highlighting/highlight.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ fn highlight_def(sema: &Semantics<RootDatabase>, krate: hir::Crate, def: Definit
362362
}
363363
}
364364

365-
if func.is_unsafe(db) {
365+
if func.is_unsafe_to_call(db) {
366366
h |= HlMod::Unsafe;
367367
}
368368
if func.is_async(db) {
@@ -508,7 +508,7 @@ fn highlight_method_call(
508508
let mut h = SymbolKind::Function.into();
509509
h |= HlMod::Associated;
510510

511-
if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(method_call) {
511+
if func.is_unsafe_to_call(sema.db) || sema.is_unsafe_method_call(method_call) {
512512
h |= HlMod::Unsafe;
513513
}
514514
if func.is_async(sema.db) {

crates/ide_completion/src/render/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
237237
if func.is_async(db) {
238238
format_to!(detail, "async ");
239239
}
240-
if func.is_unsafe(db) {
240+
if func.is_unsafe_to_call(db) {
241241
format_to!(detail, "unsafe ");
242242
}
243243

0 commit comments

Comments
 (0)