]> git.lizzy.rs Git - rust.git/blob - src/librustc_parse/parser/attr.rs
a0f535a4b954d8cbd3a8cacdf2a3af6a5c39c5a5
[rust.git] / src / librustc_parse / parser / attr.rs
1 use super::{SeqSep, Parser, TokenType, PathStyle};
2 use syntax::attr;
3 use syntax::ast;
4 use syntax::util::comments;
5 use syntax::token::{self, Nonterminal, DelimToken};
6 use syntax::tokenstream::{TokenStream, TokenTree};
7 use syntax_pos::{Span, Symbol};
8 use errors::PResult;
9
10 use log::debug;
11
12 #[derive(Debug)]
13 enum InnerAttributeParsePolicy<'a> {
14     Permitted,
15     NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
16 }
17
18 const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
19                                                      permitted in this context";
20
21 impl<'a> Parser<'a> {
22     /// Parses attributes that appear before an item.
23     pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
24         let mut attrs: Vec<ast::Attribute> = Vec::new();
25         let mut just_parsed_doc_comment = false;
26         loop {
27             debug!("parse_outer_attributes: self.token={:?}", self.token);
28             match self.token.kind {
29                 token::Pound => {
30                     let inner_error_reason = if just_parsed_doc_comment {
31                         "an inner attribute is not permitted following an outer doc comment"
32                     } else if !attrs.is_empty() {
33                         "an inner attribute is not permitted following an outer attribute"
34                     } else {
35                         DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
36                     };
37                     let inner_parse_policy =
38                         InnerAttributeParsePolicy::NotPermitted {
39                             reason: inner_error_reason,
40                             saw_doc_comment: just_parsed_doc_comment,
41                             prev_attr_sp: attrs.last().and_then(|a| Some(a.span))
42                         };
43                     let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
44                     attrs.push(attr);
45                     just_parsed_doc_comment = false;
46                 }
47                 token::DocComment(s) => {
48                     let attr = self.mk_doc_comment(s);
49                     if attr.style != ast::AttrStyle::Outer {
50                         let mut err = self.fatal("expected outer doc comment");
51                         err.note("inner doc comments like this (starting with \
52                                   `//!` or `/*!`) can only appear before items");
53                         return Err(err);
54                     }
55                     attrs.push(attr);
56                     self.bump();
57                     just_parsed_doc_comment = true;
58                 }
59                 _ => break,
60             }
61         }
62         Ok(attrs)
63     }
64
65     fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
66         let style = comments::doc_comment_style(&s.as_str());
67         attr::mk_doc_comment(style, s, self.token.span)
68     }
69
70     /// Matches `attribute = # ! [ meta_item ]`.
71     ///
72     /// If `permit_inner` is `true`, then a leading `!` indicates an inner
73     /// attribute.
74     pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
75         debug!("parse_attribute: permit_inner={:?} self.token={:?}",
76                permit_inner,
77                self.token);
78         let inner_parse_policy = if permit_inner {
79             InnerAttributeParsePolicy::Permitted
80         } else {
81             InnerAttributeParsePolicy::NotPermitted {
82                 reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
83                 saw_doc_comment: false,
84                 prev_attr_sp: None
85             }
86         };
87         self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
88     }
89
90     /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
91     /// that prescribes how to handle inner attributes.
92     fn parse_attribute_with_inner_parse_policy(
93         &mut self,
94         inner_parse_policy: InnerAttributeParsePolicy<'_>
95     ) -> PResult<'a, ast::Attribute> {
96         debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
97                inner_parse_policy,
98                self.token);
99         let (span, item, style) = match self.token.kind {
100             token::Pound => {
101                 let lo = self.token.span;
102                 self.bump();
103
104                 if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
105                     self.expected_tokens.push(TokenType::Token(token::Not));
106                 }
107
108                 let style = if self.token == token::Not {
109                     self.bump();
110                     ast::AttrStyle::Inner
111                 } else {
112                     ast::AttrStyle::Outer
113                 };
114
115                 self.expect(&token::OpenDelim(token::Bracket))?;
116                 let item = self.parse_attr_item()?;
117                 self.expect(&token::CloseDelim(token::Bracket))?;
118                 let hi = self.prev_span;
119
120                 let attr_sp = lo.to(hi);
121
122                 // Emit error if inner attribute is encountered and not permitted
123                 if style == ast::AttrStyle::Inner {
124                     if let InnerAttributeParsePolicy::NotPermitted { reason,
125                         saw_doc_comment, prev_attr_sp } = inner_parse_policy {
126                         let prev_attr_note = if saw_doc_comment {
127                             "previous doc comment"
128                         } else {
129                             "previous outer attribute"
130                         };
131
132                         let mut diagnostic = self
133                             .diagnostic()
134                             .struct_span_err(attr_sp, reason);
135
136                         if let Some(prev_attr_sp) = prev_attr_sp {
137                             diagnostic
138                                 .span_label(attr_sp, "not permitted following an outer attibute")
139                                 .span_label(prev_attr_sp, prev_attr_note);
140                         }
141
142                         diagnostic
143                             .note("inner attributes, like `#![no_std]`, annotate the item \
144                                    enclosing them, and are usually found at the beginning of \
145                                    source files. Outer attributes, like `#[test]`, annotate the \
146                                    item following them.")
147                             .emit()
148                     }
149                 }
150
151                 (attr_sp, item, style)
152             }
153             _ => {
154                 let token_str = self.this_token_to_string();
155                 return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
156             }
157         };
158
159         Ok(attr::mk_attr_from_item(style, item, span))
160     }
161
162     /// Parses an inner part of an attribute (the path and following tokens).
163     /// The tokens must be either a delimited token stream, or empty token stream,
164     /// or the "legacy" key-value form.
165     ///     PATH `(` TOKEN_STREAM `)`
166     ///     PATH `[` TOKEN_STREAM `]`
167     ///     PATH `{` TOKEN_STREAM `}`
168     ///     PATH
169     ///     PATH `=` UNSUFFIXED_LIT
170     /// The delimiters or `=` are still put into the resulting token stream.
171     pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
172         let item = match self.token.kind {
173             token::Interpolated(ref nt) => match **nt {
174                 Nonterminal::NtMeta(ref item) => Some(item.clone()),
175                 _ => None,
176             },
177             _ => None,
178         };
179         Ok(if let Some(item) = item {
180             self.bump();
181             item
182         } else {
183             let path = self.parse_path(PathStyle::Mod)?;
184             let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
185                self.check(&token::OpenDelim(DelimToken::Bracket)) ||
186                self.check(&token::OpenDelim(DelimToken::Brace)) {
187                    self.parse_token_tree().into()
188             } else if self.eat(&token::Eq) {
189                 let eq = TokenTree::token(token::Eq, self.prev_span);
190                 let mut is_interpolated_expr = false;
191                 if let token::Interpolated(nt) = &self.token.kind {
192                     if let token::NtExpr(..) = **nt {
193                         is_interpolated_expr = true;
194                     }
195                 }
196                 let token_tree = if is_interpolated_expr {
197                     // We need to accept arbitrary interpolated expressions to continue
198                     // supporting things like `doc = $expr` that work on stable.
199                     // Non-literal interpolated expressions are rejected after expansion.
200                     self.parse_token_tree()
201                 } else {
202                     self.parse_unsuffixed_lit()?.token_tree()
203                 };
204                 TokenStream::new(vec![eq.into(), token_tree.into()])
205             } else {
206                 TokenStream::default()
207             };
208             ast::AttrItem { path, tokens }
209         })
210     }
211
212     /// Parses attributes that appear after the opening of an item. These should
213     /// be preceded by an exclamation mark, but we accept and warn about one
214     /// terminated by a semicolon.
215     ///
216     /// Matches `inner_attrs*`.
217     crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
218         let mut attrs: Vec<ast::Attribute> = vec![];
219         loop {
220             match self.token.kind {
221                 token::Pound => {
222                     // Don't even try to parse if it's not an inner attribute.
223                     if !self.look_ahead(1, |t| t == &token::Not) {
224                         break;
225                     }
226
227                     let attr = self.parse_attribute(true)?;
228                     assert_eq!(attr.style, ast::AttrStyle::Inner);
229                     attrs.push(attr);
230                 }
231                 token::DocComment(s) => {
232                     // We need to get the position of this token before we bump.
233                     let attr = self.mk_doc_comment(s);
234                     if attr.style == ast::AttrStyle::Inner {
235                         attrs.push(attr);
236                         self.bump();
237                     } else {
238                         break;
239                     }
240                 }
241                 _ => break,
242             }
243         }
244         Ok(attrs)
245     }
246
247     pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
248         let lit = self.parse_lit()?;
249         debug!("checking if {:?} is unusuffixed", lit);
250
251         if !lit.kind.is_unsuffixed() {
252             let msg = "suffixed literals are not allowed in attributes";
253             self.diagnostic().struct_span_err(lit.span, msg)
254                              .help("instead of using a suffixed literal \
255                                     (1u8, 1.0f32, etc.), use an unsuffixed version \
256                                     (1, 1.0, etc.).")
257                              .emit()
258         }
259
260         Ok(lit)
261     }
262
263     /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
264     pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
265         self.expect(&token::OpenDelim(token::Paren))?;
266
267         let cfg_predicate = self.parse_meta_item()?;
268         self.expect(&token::Comma)?;
269
270         // Presumably, the majority of the time there will only be one attr.
271         let mut expanded_attrs = Vec::with_capacity(1);
272
273         while !self.check(&token::CloseDelim(token::Paren)) {
274             let lo = self.token.span.lo();
275             let item = self.parse_attr_item()?;
276             expanded_attrs.push((item, self.prev_span.with_lo(lo)));
277             self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
278         }
279
280         self.expect(&token::CloseDelim(token::Paren))?;
281         Ok((cfg_predicate, expanded_attrs))
282     }
283
284     /// Matches the following grammar (per RFC 1559).
285     ///
286     ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
287     ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
288     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
289         let nt_meta = match self.token.kind {
290             token::Interpolated(ref nt) => match **nt {
291                 token::NtMeta(ref e) => Some(e.clone()),
292                 _ => None,
293             },
294             _ => None,
295         };
296
297         if let Some(item) = nt_meta {
298             return match item.meta(item.path.span) {
299                 Some(meta) => {
300                     self.bump();
301                     Ok(meta)
302                 }
303                 None => self.unexpected(),
304             }
305         }
306
307         let lo = self.token.span;
308         let path = self.parse_path(PathStyle::Mod)?;
309         let kind = self.parse_meta_item_kind()?;
310         let span = lo.to(self.prev_span);
311         Ok(ast::MetaItem { path, kind, span })
312     }
313
314     crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
315         Ok(if self.eat(&token::Eq) {
316             ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
317         } else if self.eat(&token::OpenDelim(token::Paren)) {
318             ast::MetaItemKind::List(self.parse_meta_seq()?)
319         } else {
320             ast::MetaItemKind::Word
321         })
322     }
323
324     /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
325     fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
326         match self.parse_unsuffixed_lit() {
327             Ok(lit) => {
328                 return Ok(ast::NestedMetaItem::Literal(lit))
329             }
330             Err(ref mut err) => err.cancel(),
331         }
332
333         match self.parse_meta_item() {
334             Ok(mi) => {
335                 return Ok(ast::NestedMetaItem::MetaItem(mi))
336             }
337             Err(ref mut err) => err.cancel(),
338         }
339
340         let found = self.this_token_to_string();
341         let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
342         Err(self.diagnostic().struct_span_err(self.token.span, &msg))
343     }
344
345     /// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
346     fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
347         self.parse_seq_to_end(&token::CloseDelim(token::Paren),
348                               SeqSep::trailing_allowed(token::Comma),
349                               |p: &mut Parser<'a>| p.parse_meta_item_inner())
350     }
351 }