mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
feat: initial support for safe_kw in extern blocks
This commit is contained in:
parent
687b72c36a
commit
9f1e450c4f
12 changed files with 264 additions and 9 deletions
|
@ -148,6 +148,10 @@ impl FunctionData {
|
||||||
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
|
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_safe(&self) -> bool {
|
||||||
|
self.flags.contains(FnFlags::HAS_SAFE_KW)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_varargs(&self) -> bool {
|
pub fn is_varargs(&self) -> bool {
|
||||||
self.flags.contains(FnFlags::IS_VARARGS)
|
self.flags.contains(FnFlags::IS_VARARGS)
|
||||||
}
|
}
|
||||||
|
|
|
@ -754,6 +754,7 @@ bitflags::bitflags! {
|
||||||
const HAS_ASYNC_KW = 1 << 4;
|
const HAS_ASYNC_KW = 1 << 4;
|
||||||
const HAS_UNSAFE_KW = 1 << 5;
|
const HAS_UNSAFE_KW = 1 << 5;
|
||||||
const IS_VARARGS = 1 << 6;
|
const IS_VARARGS = 1 << 6;
|
||||||
|
const HAS_SAFE_KW = 1 << 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -440,6 +440,9 @@ impl<'a> Ctx<'a> {
|
||||||
if func.unsafe_token().is_some() {
|
if func.unsafe_token().is_some() {
|
||||||
flags |= FnFlags::HAS_UNSAFE_KW;
|
flags |= FnFlags::HAS_UNSAFE_KW;
|
||||||
}
|
}
|
||||||
|
if func.safe_token().is_some() {
|
||||||
|
flags |= FnFlags::HAS_SAFE_KW;
|
||||||
|
}
|
||||||
if has_var_args {
|
if has_var_args {
|
||||||
flags |= FnFlags::IS_VARARGS;
|
flags |= FnFlags::IS_VARARGS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,6 +278,9 @@ impl Printer<'_> {
|
||||||
if flags.contains(FnFlags::HAS_UNSAFE_KW) {
|
if flags.contains(FnFlags::HAS_UNSAFE_KW) {
|
||||||
w!(self, "unsafe ");
|
w!(self, "unsafe ");
|
||||||
}
|
}
|
||||||
|
if flags.contains(FnFlags::HAS_SAFE_KW) {
|
||||||
|
w!(self, "safe ");
|
||||||
|
}
|
||||||
if let Some(abi) = abi {
|
if let Some(abi) = abi {
|
||||||
w!(self, "extern \"{}\" ", abi);
|
w!(self, "extern \"{}\" ", abi);
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,10 +257,12 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
match func.lookup(db.upcast()).container {
|
let loc = func.lookup(db.upcast());
|
||||||
|
match loc.container {
|
||||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||||
// 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
|
||||||
// `"rust-intrinsic"` ABI there are a few exceptions.
|
// it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a
|
||||||
|
// few exceptions.
|
||||||
let id = block.lookup(db.upcast()).id;
|
let id = block.lookup(db.upcast()).id;
|
||||||
|
|
||||||
let is_intrinsic =
|
let is_intrinsic =
|
||||||
|
@ -270,8 +272,8 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
|
||||||
// Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
|
// Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
|
||||||
!data.attrs.by_key(&sym::rustc_safe_intrinsic).exists()
|
!data.attrs.by_key(&sym::rustc_safe_intrinsic).exists()
|
||||||
} else {
|
} else {
|
||||||
// Extern items are always unsafe
|
// Extern items without `safe` modifier are always unsafe
|
||||||
true
|
!db.function_data(func).is_safe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -554,7 +554,7 @@ fn main() {
|
||||||
r#"
|
r#"
|
||||||
//- /ed2021.rs crate:ed2021 edition:2021
|
//- /ed2021.rs crate:ed2021 edition:2021
|
||||||
#[rustc_deprecated_safe_2024]
|
#[rustc_deprecated_safe_2024]
|
||||||
unsafe fn safe() -> u8 {
|
unsafe fn safe_fn() -> u8 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
//- /ed2024.rs crate:ed2024 edition:2024
|
//- /ed2024.rs crate:ed2024 edition:2024
|
||||||
|
@ -564,7 +564,7 @@ unsafe fn not_safe() -> u8 {
|
||||||
}
|
}
|
||||||
//- /main.rs crate:main deps:ed2021,ed2024
|
//- /main.rs crate:main deps:ed2021,ed2024
|
||||||
fn main() {
|
fn main() {
|
||||||
ed2021::safe();
|
ed2021::safe_fn();
|
||||||
ed2024::not_safe();
|
ed2024::not_safe();
|
||||||
//^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
|
//^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,6 +135,11 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
|
||||||
has_mods = true;
|
has_mods = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.at(T![safe]) {
|
||||||
|
p.eat(T![safe]);
|
||||||
|
has_mods = true;
|
||||||
|
}
|
||||||
|
|
||||||
if p.at(T![extern]) {
|
if p.at(T![extern]) {
|
||||||
has_extern = true;
|
has_extern = true;
|
||||||
has_mods = true;
|
has_mods = true;
|
||||||
|
@ -189,6 +194,7 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
|
||||||
T![fn] => fn_(p, m),
|
T![fn] => fn_(p, m),
|
||||||
|
|
||||||
T![const] if p.nth(1) != T!['{'] => consts::konst(p, m),
|
T![const] if p.nth(1) != T!['{'] => consts::konst(p, m),
|
||||||
|
T![static] if matches!(p.nth(1), IDENT | T![_] | T![mut]) => consts::static_(p, m),
|
||||||
|
|
||||||
T![trait] => traits::trait_(p, m),
|
T![trait] => traits::trait_(p, m),
|
||||||
T![impl] => traits::impl_(p, m),
|
T![impl] => traits::impl_(p, m),
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,208 @@
|
||||||
|
SOURCE_FILE
|
||||||
|
EXTERN_BLOCK
|
||||||
|
UNSAFE_KW "unsafe"
|
||||||
|
WHITESPACE " "
|
||||||
|
ABI
|
||||||
|
EXTERN_KW "extern"
|
||||||
|
WHITESPACE " "
|
||||||
|
EXTERN_ITEM_LIST
|
||||||
|
L_CURLY "{"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
FN
|
||||||
|
COMMENT "// sqrt (from libm) may be called with any `f64`"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
VISIBILITY
|
||||||
|
PUB_KW "pub"
|
||||||
|
WHITESPACE " "
|
||||||
|
SAFE_KW "safe"
|
||||||
|
WHITESPACE " "
|
||||||
|
FN_KW "fn"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "sqrt"
|
||||||
|
PARAM_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
PARAM
|
||||||
|
IDENT_PAT
|
||||||
|
NAME
|
||||||
|
IDENT "x"
|
||||||
|
COLON ":"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "f64"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
RET_TYPE
|
||||||
|
THIN_ARROW "->"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "f64"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n\n "
|
||||||
|
FN
|
||||||
|
COMMENT "// strlen (from libc) requires a valid pointer,"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
COMMENT "// so we mark it as being an unsafe fn"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
VISIBILITY
|
||||||
|
PUB_KW "pub"
|
||||||
|
WHITESPACE " "
|
||||||
|
UNSAFE_KW "unsafe"
|
||||||
|
WHITESPACE " "
|
||||||
|
FN_KW "fn"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "strlen"
|
||||||
|
PARAM_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
PARAM
|
||||||
|
IDENT_PAT
|
||||||
|
NAME
|
||||||
|
IDENT "p"
|
||||||
|
COLON ":"
|
||||||
|
WHITESPACE " "
|
||||||
|
PTR_TYPE
|
||||||
|
STAR "*"
|
||||||
|
CONST_KW "const"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "c_char"
|
||||||
|
R_PAREN ")"
|
||||||
|
WHITESPACE " "
|
||||||
|
RET_TYPE
|
||||||
|
THIN_ARROW "->"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "usize"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n\n "
|
||||||
|
FN
|
||||||
|
COMMENT "// this function doesn't say safe or unsafe, so it defaults to unsafe"
|
||||||
|
WHITESPACE "\n "
|
||||||
|
VISIBILITY
|
||||||
|
PUB_KW "pub"
|
||||||
|
WHITESPACE " "
|
||||||
|
FN_KW "fn"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "free"
|
||||||
|
PARAM_LIST
|
||||||
|
L_PAREN "("
|
||||||
|
PARAM
|
||||||
|
IDENT_PAT
|
||||||
|
NAME
|
||||||
|
IDENT "p"
|
||||||
|
COLON ":"
|
||||||
|
WHITESPACE " "
|
||||||
|
PTR_TYPE
|
||||||
|
STAR "*"
|
||||||
|
MUT_KW "mut"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "core"
|
||||||
|
COLON2 "::"
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "ffi"
|
||||||
|
COLON2 "::"
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "c_void"
|
||||||
|
R_PAREN ")"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n\n "
|
||||||
|
STATIC
|
||||||
|
VISIBILITY
|
||||||
|
PUB_KW "pub"
|
||||||
|
WHITESPACE " "
|
||||||
|
SAFE_KW "safe"
|
||||||
|
WHITESPACE " "
|
||||||
|
STATIC_KW "static"
|
||||||
|
WHITESPACE " "
|
||||||
|
MUT_KW "mut"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "COUNTER"
|
||||||
|
COLON ":"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "i32"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n\n "
|
||||||
|
STATIC
|
||||||
|
VISIBILITY
|
||||||
|
PUB_KW "pub"
|
||||||
|
WHITESPACE " "
|
||||||
|
UNSAFE_KW "unsafe"
|
||||||
|
WHITESPACE " "
|
||||||
|
STATIC_KW "static"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "IMPORTANT_BYTES"
|
||||||
|
COLON ":"
|
||||||
|
WHITESPACE " "
|
||||||
|
ARRAY_TYPE
|
||||||
|
L_BRACK "["
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "u8"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE " "
|
||||||
|
CONST_ARG
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "256"
|
||||||
|
R_BRACK "]"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n\n "
|
||||||
|
STATIC
|
||||||
|
VISIBILITY
|
||||||
|
PUB_KW "pub"
|
||||||
|
WHITESPACE " "
|
||||||
|
SAFE_KW "safe"
|
||||||
|
WHITESPACE " "
|
||||||
|
STATIC_KW "static"
|
||||||
|
WHITESPACE " "
|
||||||
|
NAME
|
||||||
|
IDENT "LINES"
|
||||||
|
COLON ":"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "SyncUnsafeCell"
|
||||||
|
GENERIC_ARG_LIST
|
||||||
|
L_ANGLE "<"
|
||||||
|
TYPE_ARG
|
||||||
|
PATH_TYPE
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "i32"
|
||||||
|
R_ANGLE ">"
|
||||||
|
SEMICOLON ";"
|
||||||
|
WHITESPACE "\n"
|
||||||
|
R_CURLY "}"
|
||||||
|
WHITESPACE "\n"
|
|
@ -0,0 +1,17 @@
|
||||||
|
unsafe extern {
|
||||||
|
// sqrt (from libm) may be called with any `f64`
|
||||||
|
pub safe fn sqrt(x: f64) -> f64;
|
||||||
|
|
||||||
|
// strlen (from libc) requires a valid pointer,
|
||||||
|
// so we mark it as being an unsafe fn
|
||||||
|
pub unsafe fn strlen(p: *const c_char) -> usize;
|
||||||
|
|
||||||
|
// this function doesn't say safe or unsafe, so it defaults to unsafe
|
||||||
|
pub fn free(p: *mut core::ffi::c_void);
|
||||||
|
|
||||||
|
pub safe static mut COUNTER: i32;
|
||||||
|
|
||||||
|
pub unsafe static IMPORTANT_BYTES: [u8; 256];
|
||||||
|
|
||||||
|
pub safe static LINES: SyncUnsafeCell<i32>;
|
||||||
|
}
|
|
@ -190,7 +190,7 @@ UseTreeList =
|
||||||
|
|
||||||
Fn =
|
Fn =
|
||||||
Attr* Visibility?
|
Attr* Visibility?
|
||||||
'default'? 'const'? 'async'? 'gen'? 'unsafe'? Abi?
|
'default'? 'const'? 'async'? 'gen'? 'unsafe'? 'safe'? Abi?
|
||||||
'fn' Name GenericParamList? ParamList RetType? WhereClause?
|
'fn' Name GenericParamList? ParamList RetType? WhereClause?
|
||||||
(body:BlockExpr | ';')
|
(body:BlockExpr | ';')
|
||||||
|
|
||||||
|
@ -284,6 +284,7 @@ Const =
|
||||||
|
|
||||||
Static =
|
Static =
|
||||||
Attr* Visibility?
|
Attr* Visibility?
|
||||||
|
'unsafe'? 'safe'?
|
||||||
'static' 'mut'? Name ':' Type
|
'static' 'mut'? Name ':' Type
|
||||||
('=' body:Expr)? ';'
|
('=' body:Expr)? ';'
|
||||||
|
|
||||||
|
|
|
@ -668,6 +668,8 @@ impl Fn {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn gen_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![gen]) }
|
pub fn gen_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![gen]) }
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn safe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![safe]) }
|
||||||
|
#[inline]
|
||||||
pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
|
pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1761,7 +1763,11 @@ impl Static {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
|
pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
|
||||||
#[inline]
|
#[inline]
|
||||||
|
pub fn safe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![safe]) }
|
||||||
|
#[inline]
|
||||||
pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
|
pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
|
||||||
|
#[inline]
|
||||||
|
pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|
Loading…
Reference in a new issue