about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs35
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs1
2 files changed, 33 insertions, 3 deletions
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 4acc610d8c4..2dd19f6c20a 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -7,7 +7,7 @@ use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Delimiter};
 use rustc_errors::{codes::*, Diag, PResult};
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{sym, symbol::kw, BytePos, Span};
 use thin_vec::ThinVec;
 use tracing::debug;
 
@@ -252,9 +252,23 @@ impl<'a> Parser<'a> {
         maybe_whole!(self, NtMeta, |attr| attr.into_inner());
 
         let do_parse = |this: &mut Self| {
+            let is_unsafe = this.eat_keyword(kw::Unsafe);
+            let unsafety = if is_unsafe {
+                let unsafe_span = this.prev_token.span;
+                this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
+                this.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
+
+                ast::Unsafe::Yes(unsafe_span)
+            } else {
+                ast::Unsafe::No
+            };
+
             let path = this.parse_path(PathStyle::Mod)?;
             let args = this.parse_attr_args()?;
-            Ok(ast::AttrItem { path, args, tokens: None })
+            if is_unsafe {
+                this.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
+            }
+            Ok(ast::AttrItem { unsafety, path, args, tokens: None })
         };
         // Attr items don't have attributes
         if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }
@@ -375,10 +389,25 @@ impl<'a> Parser<'a> {
         }
 
         let lo = self.token.span;
+        let is_unsafe = self.eat_keyword(kw::Unsafe);
+        let unsafety = if is_unsafe {
+            let unsafe_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
+            self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
+
+            ast::Unsafe::Yes(unsafe_span)
+        } else {
+            ast::Unsafe::No
+        };
+
         let path = self.parse_path(PathStyle::Mod)?;
         let kind = self.parse_meta_item_kind()?;
+        if is_unsafe {
+            self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
+        }
         let span = lo.to(self.prev_token.span);
-        Ok(ast::MetaItem { path, kind, span })
+
+        Ok(ast::MetaItem { unsafety, path, kind, span })
     }
 
     pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index b91ef1ae1f3..58342ff8290 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -42,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
 pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
     let item = attr.get_normal_item();
     Ok(MetaItem {
+        unsafety: item.unsafety,
         span: attr.span,
         path: item.path.clone(),
         kind: match &item.args {