about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs14
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast457
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs20
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram5
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs3
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/validation/block.rs2
8 files changed, 534 insertions, 11 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index feffcb7ce5b..85ec02ae073 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/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<Attr> {
-        let ctxt = tt.first()?.first_span().ctx;
+    fn from_tt(db: &dyn ExpandDatabase, mut tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
+        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<Item = &[tt::TokenTree]>)> {
     let mut parts = subtree
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index b6c6753755c..20e998846b3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
index c13a1943792..82e4d661488 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast
new file mode 100644
index 00000000000..b1ac60b530e
--- /dev/null
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs
new file mode 100644
index 00000000000..57b7bb7170d
--- /dev/null
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 8a775dd8749..8c772b9c7a2 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index c82bc4151ac..98186c5473d 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -778,7 +778,10 @@ impl Meta {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
     pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs b/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
index 8eb4a10a3f5..fe3d61bef16 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
@@ -9,7 +9,7 @@ use crate::{
 pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<SyntaxError>) {
     if let Some(parent) = block.syntax().parent() {
         match parent.kind() {
-            FN | EXPR_STMT | STMT_LIST => return,
+            FN | EXPR_STMT | STMT_LIST | MACRO_STMTS => return,
             _ => {}
         }
     }