diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index feffcb7ce5..85ec02ae07 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -252,8 +252,18 @@ impl Attr { Some(Attr { id, path, input, ctxt: span.ctx }) } - fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree], id: AttrId) -> Option { - let ctxt = tt.first()?.first_span().ctx; + fn from_tt(db: &dyn ExpandDatabase, mut tt: &[tt::TokenTree], id: AttrId) -> Option { + if matches!(tt, + [tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, .. })), ..] + if text == "unsafe" + ) { + match tt.get(1) { + Some(tt::TokenTree::Subtree(subtree)) => tt = &subtree.token_trees, + _ => return None, + } + } + let first = &tt.first()?; + let ctxt = first.first_span().ctx; let path_end = tt .iter() .position(|tt| { @@ -435,7 +445,7 @@ fn inner_attributes( // Input subtree is: `(cfg, $(attr),+)` // Split it up into a `cfg` subtree and the `attr` subtrees. -pub fn parse_cfg_attr_input( +fn parse_cfg_attr_input( subtree: &Subtree, ) -> Option<(&[tt::TokenTree], impl Iterator)> { let mut parts = subtree diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index b6c6753755..20e998846b 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -609,6 +609,9 @@ fn main() {} #[export_name = "main"] fn __cortex_m_rt_main_trampoline() {} +#[unsafe(export_name = "main")] +fn __cortex_m_rt_main_trampoline_unsafe() {} + #[test] fn test_foo() {} @@ -628,13 +631,14 @@ mod not_a_root { "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..253, name: \"\", kind: Module })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..331, name: \"\", kind: Module })", "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", "(Bin, NavigationTarget { file_id: FileId(0), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 78..102, focus_range: 89..97, name: \"test_foo\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 104..155, focus_range: 136..150, name: \"test_full_path\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 157..191, focus_range: 178..186, name: \"test_foo\", kind: Function })", - "(Bench, NavigationTarget { file_id: FileId(0), full_range: 193..215, focus_range: 205..210, name: \"bench\", kind: Function })", + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 78..154, focus_range: 113..149, name: \"__cortex_m_rt_main_trampoline_unsafe\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 156..180, focus_range: 167..175, name: \"test_foo\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 182..233, focus_range: 214..228, name: \"test_full_path\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 235..269, focus_range: 256..264, name: \"test_foo\", kind: Function })", + "(Bench, NavigationTarget { file_id: FileId(0), full_range: 271..293, focus_range: 283..288, name: \"bench\", kind: Function })", ] "#]], ); diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs index c13a194379..82e4d66148 100644 --- a/crates/parser/src/grammar/attributes.rs +++ b/crates/parser/src/grammar/attributes.rs @@ -36,8 +36,33 @@ fn attr(p: &mut Parser<'_>, inner: bool) { attr.complete(p, ATTR); } +// test metas +// #![simple_ident] +// #![simple::path] +// #![simple_ident_expr = ""] +// #![simple::path::Expr = ""] +// #![simple_ident_tt(a b c)] +// #![simple_ident_tt[a b c]] +// #![simple_ident_tt{a b c}] +// #![simple::path::tt(a b c)] +// #![simple::path::tt[a b c]] +// #![simple::path::tt{a b c}] +// #![unsafe(simple_ident)] +// #![unsafe(simple::path)] +// #![unsafe(simple_ident_expr = "")] +// #![unsafe(simple::path::Expr = "")] +// #![unsafe(simple_ident_tt(a b c))] +// #![unsafe(simple_ident_tt[a b c])] +// #![unsafe(simple_ident_tt{a b c})] +// #![unsafe(simple::path::tt(a b c))] +// #![unsafe(simple::path::tt[a b c])] +// #![unsafe(simple::path::tt{a b c})] pub(super) fn meta(p: &mut Parser<'_>) { let meta = p.start(); + let is_unsafe = p.eat(T![unsafe]); + if is_unsafe { + p.expect(T!['(']); + } paths::use_path(p); match p.current() { @@ -50,6 +75,9 @@ pub(super) fn meta(p: &mut Parser<'_>) { T!['('] | T!['['] | T!['{'] => items::token_tree(p), _ => {} } + if is_unsafe { + p.expect(T![')']); + } meta.complete(p, META); } diff --git a/crates/parser/test_data/parser/inline/ok/0213_metas.rast b/crates/parser/test_data/parser/inline/ok/0213_metas.rast new file mode 100644 index 0000000000..b1ac60b530 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0213_metas.rast @@ -0,0 +1,457 @@ +SOURCE_FILE + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "Expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "Expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0213_metas.rs b/crates/parser/test_data/parser/inline/ok/0213_metas.rs new file mode 100644 index 0000000000..57b7bb7170 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0213_metas.rs @@ -0,0 +1,20 @@ +#![simple_ident] +#![simple::path] +#![simple_ident_expr = ""] +#![simple::path::Expr = ""] +#![simple_ident_tt(a b c)] +#![simple_ident_tt[a b c]] +#![simple_ident_tt{a b c}] +#![simple::path::tt(a b c)] +#![simple::path::tt[a b c]] +#![simple::path::tt{a b c}] +#![unsafe(simple_ident)] +#![unsafe(simple::path)] +#![unsafe(simple_ident_expr = "")] +#![unsafe(simple::path::Expr = "")] +#![unsafe(simple_ident_tt(a b c))] +#![unsafe(simple_ident_tt[a b c])] +#![unsafe(simple_ident_tt{a b c})] +#![unsafe(simple::path::tt(a b c))] +#![unsafe(simple::path::tt[a b c])] +#![unsafe(simple::path::tt{a b c})] diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 8a775dd874..8c772b9c7a 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -314,7 +314,9 @@ Attr = '#' '!'? '[' Meta ']' Meta = - Path ('=' Expr | TokenTree)? + 'unsafe' '(' Path ('=' Expr | TokenTree)? ')' +| Path ('=' Expr | TokenTree)? + //****************************// // Statements and Expressions // @@ -391,7 +393,6 @@ FormatArgsExpr = FormatArgsArg = (Name '=')? Expr -# MacroCallExpr MacroExpr = MacroCall diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index c82bc4151a..98186c5473 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -778,7 +778,10 @@ impl Meta { pub fn expr(&self) -> Option { support::child(&self.syntax) } pub fn path(&self) -> Option { support::child(&self.syntax) } pub fn token_tree(&self) -> Option { support::child(&self.syntax) } + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/syntax/src/validation/block.rs b/crates/syntax/src/validation/block.rs index 8eb4a10a3f..fe3d61bef1 100644 --- a/crates/syntax/src/validation/block.rs +++ b/crates/syntax/src/validation/block.rs @@ -9,7 +9,7 @@ use crate::{ pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec) { if let Some(parent) = block.syntax().parent() { match parent.kind() { - FN | EXPR_STMT | STMT_LIST => return, + FN | EXPR_STMT | STMT_LIST | MACRO_STMTS => return, _ => {} } }