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