]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_parse/src/parser/attr.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / compiler / rustc_parse / src / parser / attr.rs
CommitLineData
a2a8927a 1use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
3dfed10e 2use rustc_ast as ast;
74b04a01
XL
3use rustc_ast::attr;
4use rustc_ast::token::{self, Nonterminal};
74b04a01 5use rustc_ast_pretty::pprust;
c295e0f8
XL
6use rustc_errors::{error_code, DiagnosticBuilder, PResult};
7use rustc_span::{sym, BytePos, Span};
cdc7bbd5 8use std::convert::TryInto;
9fa01778 9
3dfed10e 10use tracing::debug;
223e47cc 11
fc512014 12// Public for rustfmt usage
8faf50e0 13#[derive(Debug)]
fc512014 14pub enum InnerAttrPolicy<'a> {
5bcae85e 15 Permitted,
ba9703b0 16 Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
5bcae85e
SL
17}
18
0731742a
XL
19const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
20 permitted in this context";
5bcae85e 21
ba9703b0
XL
22pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
23 reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
24 saw_doc_comment: false,
25 prev_attr_sp: None,
26};
27
c295e0f8
XL
28enum OuterAttributeType {
29 DocComment,
30 DocBlockComment,
31 Attribute,
32}
33
92a42be0 34impl<'a> Parser<'a> {
e1599b0c 35 /// Parses attributes that appear before an item.
6a06907d 36 pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
1a4d82fc 37 let mut attrs: Vec<ast::Attribute> = Vec::new();
5bcae85e 38 let mut just_parsed_doc_comment = false;
cdc7bbd5 39 let start_pos = self.token_cursor.num_next_calls;
223e47cc 40 loop {
29967ef6 41 let attr = if self.check(&token::Pound) {
ba9703b0
XL
42 let inner_error_reason = if just_parsed_doc_comment {
43 "an inner attribute is not permitted following an outer doc comment"
44 } else if !attrs.is_empty() {
45 "an inner attribute is not permitted following an outer attribute"
46 } else {
47 DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
48 };
49 let inner_parse_policy = InnerAttrPolicy::Forbidden {
50 reason: inner_error_reason,
51 saw_doc_comment: just_parsed_doc_comment,
52 prev_attr_sp: attrs.last().map(|a| a.span),
53 };
ba9703b0 54 just_parsed_doc_comment = false;
29967ef6 55 Some(self.parse_attribute(inner_parse_policy)?)
3dfed10e 56 } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
29967ef6 57 if attr_style != ast::AttrStyle::Outer {
c295e0f8
XL
58 let span = self.token.span;
59 let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
60 span,
61 "expected outer doc comment",
62 error_code!(E0753),
63 );
64 if let Some(replacement_span) = self.annotate_following_item_if_applicable(
65 &mut err,
66 span,
67 match comment_kind {
68 token::CommentKind::Line => OuterAttributeType::DocComment,
69 token::CommentKind::Block => OuterAttributeType::DocBlockComment,
70 },
71 ) {
72 err.note(
73 "inner doc comments like this (starting with `//!` or `/*!`) can \
74 only appear before items",
75 );
76 err.span_suggestion_verbose(
77 replacement_span,
78 "you might have meant to write a regular comment",
79 String::new(),
80 rustc_errors::Applicability::MachineApplicable,
81 );
82 }
83 err.emit();
223e47cc 84 }
ba9703b0
XL
85 self.bump();
86 just_parsed_doc_comment = true;
136023e0
XL
87 // Always make an outer attribute - this allows us to recover from a misplaced
88 // inner attribute.
89 Some(attr::mk_doc_comment(
90 comment_kind,
91 ast::AttrStyle::Outer,
92 data,
93 self.prev_token.span,
94 ))
29967ef6
XL
95 } else {
96 None
97 };
98
99 if let Some(attr) = attr {
100 attrs.push(attr);
ba9703b0
XL
101 } else {
102 break;
223e47cc
LB
103 }
104 }
cdc7bbd5 105 Ok(AttrWrapper::new(attrs.into(), start_pos))
223e47cc
LB
106 }
107
e1599b0c 108 /// Matches `attribute = # ! [ meta_item ]`.
29967ef6 109 /// `inner_parse_policy` prescribes how to handle inner attributes.
fc512014
XL
110 // Public for rustfmt usage.
111 pub fn parse_attribute(
e74abb32 112 &mut self,
ba9703b0 113 inner_parse_policy: InnerAttrPolicy<'_>,
e74abb32 114 ) -> PResult<'a, ast::Attribute> {
dfeec247 115 debug!(
29967ef6 116 "parse_attribute: inner_parse_policy={:?} self.token={:?}",
dfeec247
XL
117 inner_parse_policy, self.token
118 );
ba9703b0 119 let lo = self.token.span;
c295e0f8 120 // Attributes can't have attributes of their own [Editor's note: not with that attitude]
6a06907d 121 self.collect_tokens_no_attrs(|this| {
29967ef6
XL
122 if this.eat(&token::Pound) {
123 let style = if this.eat(&token::Not) {
124 ast::AttrStyle::Inner
125 } else {
126 ast::AttrStyle::Outer
127 };
1a4d82fc 128
29967ef6
XL
129 this.expect(&token::OpenDelim(token::Bracket))?;
130 let item = this.parse_attr_item(false)?;
131 this.expect(&token::CloseDelim(token::Bracket))?;
132 let attr_sp = lo.to(this.prev_token.span);
133
134 // Emit error if inner attribute is encountered and forbidden.
135 if style == ast::AttrStyle::Inner {
136 this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
137 }
138
5869c6ff 139 Ok(attr::mk_attr_from_item(item, None, style, attr_sp))
29967ef6
XL
140 } else {
141 let token_str = pprust::token_to_string(&this.token);
142 let msg = &format!("expected `#`, found `{}`", token_str);
143 Err(this.struct_span_err(this.token.span, msg))
144 }
5869c6ff 145 })
ba9703b0 146 }
1a4d82fc 147
c295e0f8
XL
148 fn annotate_following_item_if_applicable(
149 &self,
150 err: &mut DiagnosticBuilder<'_>,
151 span: Span,
152 attr_type: OuterAttributeType,
153 ) -> Option<Span> {
154 let mut snapshot = self.clone();
155 let lo = span.lo()
156 + BytePos(match attr_type {
157 OuterAttributeType::Attribute => 1,
158 _ => 2,
159 });
160 let hi = lo + BytePos(1);
161 let replacement_span = span.with_lo(lo).with_hi(hi);
162 if let OuterAttributeType::DocBlockComment | OuterAttributeType::DocComment = attr_type {
163 snapshot.bump();
164 }
165 loop {
166 // skip any other attributes, we want the item
167 if snapshot.token.kind == token::Pound {
168 if let Err(mut err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) {
169 err.cancel();
170 return Some(replacement_span);
171 }
172 } else {
173 break;
174 }
175 }
176 match snapshot.parse_item_common(
177 AttrWrapper::empty(),
178 true,
179 false,
a2a8927a 180 FnParseMode { req_name: |_| true, req_body: true },
c295e0f8
XL
181 ForceCollect::No,
182 ) {
183 Ok(Some(item)) => {
184 let attr_name = match attr_type {
185 OuterAttributeType::Attribute => "attribute",
186 _ => "doc comment",
187 };
188 err.span_label(
189 item.span,
190 &format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()),
191 );
192 err.span_suggestion_verbose(
193 replacement_span,
194 &format!(
195 "to annotate the {}, change the {} from inner to outer style",
196 item.kind.descr(),
197 attr_name
198 ),
199 (match attr_type {
200 OuterAttributeType::Attribute => "",
201 OuterAttributeType::DocBlockComment => "*",
202 OuterAttributeType::DocComment => "/",
203 })
204 .to_string(),
205 rustc_errors::Applicability::MachineApplicable,
206 );
207 return None;
208 }
209 Err(mut item_err) => {
210 item_err.cancel();
211 }
212 Ok(None) => {}
213 }
214 Some(replacement_span)
215 }
216
ba9703b0
XL
217 pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
218 if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
219 let prev_attr_note =
220 if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
416331ca 221
ba9703b0
XL
222 let mut diag = self.struct_span_err(attr_sp, reason);
223
224 if let Some(prev_attr_sp) = prev_attr_sp {
225 diag.span_label(attr_sp, "not permitted following an outer attribute")
226 .span_label(prev_attr_sp, prev_attr_note);
1a4d82fc 227 }
1a4d82fc 228
ba9703b0 229 diag.note(
c295e0f8
XL
230 "inner attributes, like `#![no_std]`, annotate the item enclosing them, and \
231 are usually found at the beginning of source files",
232 );
233 if self
234 .annotate_following_item_if_applicable(
235 &mut diag,
236 attr_sp,
237 OuterAttributeType::Attribute,
238 )
239 .is_some()
240 {
241 diag.note("outer attributes, like `#[test]`, annotate the item following them");
242 };
243 diag.emit();
ba9703b0 244 }
223e47cc
LB
245 }
246
e1599b0c 247 /// Parses an inner part of an attribute (the path and following tokens).
b7449926
XL
248 /// The tokens must be either a delimited token stream, or empty token stream,
249 /// or the "legacy" key-value form.
e1599b0c
XL
250 /// PATH `(` TOKEN_STREAM `)`
251 /// PATH `[` TOKEN_STREAM `]`
252 /// PATH `{` TOKEN_STREAM `}`
253 /// PATH
e74abb32 254 /// PATH `=` UNSUFFIXED_LIT
b7449926 255 /// The delimiters or `=` are still put into the resulting token stream.
29967ef6 256 pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
e74abb32 257 let item = match self.token.kind {
9fa01778 258 token::Interpolated(ref nt) => match **nt {
74b04a01 259 Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()),
cc61c64b
XL
260 _ => None,
261 },
262 _ => None,
263 };
e74abb32 264 Ok(if let Some(item) = item {
cc61c64b 265 self.bump();
e74abb32 266 item
cc61c64b 267 } else {
29967ef6
XL
268 let do_parse = |this: &mut Self| {
269 let path = this.parse_path(PathStyle::Mod)?;
270 let args = this.parse_attr_args()?;
271 Ok(ast::AttrItem { path, args, tokens: None })
272 };
6a06907d
XL
273 // Attr items don't have attributes
274 if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }?
cc61c64b
XL
275 })
276 }
277
e1599b0c 278 /// Parses attributes that appear after the opening of an item. These should
1a4d82fc 279 /// be preceded by an exclamation mark, but we accept and warn about one
c34b1796 280 /// terminated by a semicolon.
e1599b0c
XL
281 ///
282 /// Matches `inner_attrs*`.
94b46f34 283 crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
c34b1796 284 let mut attrs: Vec<ast::Attribute> = vec![];
223e47cc 285 loop {
cdc7bbd5 286 let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
ba9703b0 287 // Only try to parse if it is an inner attribute (has `!`).
29967ef6
XL
288 let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
289 Some(self.parse_attribute(InnerAttrPolicy::Permitted)?)
3dfed10e 290 } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
29967ef6 291 if attr_style == ast::AttrStyle::Inner {
ba9703b0 292 self.bump();
29967ef6 293 Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span))
ba9703b0 294 } else {
29967ef6 295 None
223e47cc 296 }
29967ef6
XL
297 } else {
298 None
299 };
300 if let Some(attr) = attr {
cdc7bbd5
XL
301 let end_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
302 // If we are currently capturing tokens, mark the location of this inner attribute.
303 // If capturing ends up creating a `LazyTokenStream`, we will include
304 // this replace range with it, removing the inner attribute from the final
305 // `AttrAnnotatedTokenStream`. Inner attributes are stored in the parsed AST note.
306 // During macro expansion, they are selectively inserted back into the
307 // token stream (the first inner attribute is remoevd each time we invoke the
308 // corresponding macro).
309 let range = start_pos..end_pos;
310 if let Capturing::Yes = self.capture_state.capturing {
311 self.capture_state.inner_attr_ranges.insert(attr.id, (range, vec![]));
312 }
29967ef6 313 attrs.push(attr);
ba9703b0
XL
314 } else {
315 break;
223e47cc
LB
316 }
317 }
92a42be0 318 Ok(attrs)
223e47cc
LB
319 }
320
60c5eb7d 321 crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
9e0c209e 322 let lit = self.parse_lit()?;
416331ca 323 debug!("checking if {:?} is unusuffixed", lit);
9e0c209e 324
e74abb32 325 if !lit.kind.is_unsuffixed() {
ba9703b0 326 self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes")
dfeec247 327 .help(
ba9703b0
XL
328 "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
329 use an unsuffixed version (`1`, `1.0`, etc.)",
dfeec247 330 )
74b04a01 331 .emit();
9e0c209e
SL
332 }
333
334 Ok(lit)
335 }
336
e74abb32 337 /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
60c5eb7d 338 pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
e74abb32
XL
339 let cfg_predicate = self.parse_meta_item()?;
340 self.expect(&token::Comma)?;
341
342 // Presumably, the majority of the time there will only be one attr.
343 let mut expanded_attrs = Vec::with_capacity(1);
60c5eb7d
XL
344 while self.token.kind != token::Eof {
345 let lo = self.token.span;
29967ef6 346 let item = self.parse_attr_item(true)?;
74b04a01 347 expanded_attrs.push((item, lo.to(self.prev_token.span)));
60c5eb7d
XL
348 if !self.eat(&token::Comma) {
349 break;
350 }
e74abb32
XL
351 }
352
e74abb32
XL
353 Ok((cfg_predicate, expanded_attrs))
354 }
355
60c5eb7d
XL
356 /// Matches `COMMASEP(meta_item_inner)`.
357 crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
358 // Presumably, the majority of the time there will only be one attr.
359 let mut nmis = Vec::with_capacity(1);
360 while self.token.kind != token::Eof {
361 nmis.push(self.parse_meta_item_inner()?);
362 if !self.eat(&token::Comma) {
363 break;
364 }
365 }
366 Ok(nmis)
367 }
368
e1599b0c 369 /// Matches the following grammar (per RFC 1559).
9e0c209e 370 ///
e74abb32 371 /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
e1599b0c 372 /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
476ff2be 373 pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
dc9dc135 374 let nt_meta = match self.token.kind {
9fa01778 375 token::Interpolated(ref nt) => match **nt {
c30ab7b3
SL
376 token::NtMeta(ref e) => Some(e.clone()),
377 _ => None,
378 },
7453a54e 379 _ => None,
1a4d82fc
JJ
380 };
381
e74abb32
XL
382 if let Some(item) = nt_meta {
383 return match item.meta(item.path.span) {
384 Some(meta) => {
385 self.bump();
386 Ok(meta)
387 }
388 None => self.unexpected(),
dfeec247 389 };
1a4d82fc
JJ
390 }
391
dc9dc135 392 let lo = self.token.span;
532ac7d7 393 let path = self.parse_path(PathStyle::Mod)?;
e74abb32 394 let kind = self.parse_meta_item_kind()?;
74b04a01 395 let span = lo.to(self.prev_token.span);
e74abb32 396 Ok(ast::MetaItem { path, kind, span })
cc61c64b
XL
397 }
398
94b46f34 399 crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
cc61c64b 400 Ok(if self.eat(&token::Eq) {
476ff2be 401 ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
dfeec247
XL
402 } else if self.check(&token::OpenDelim(token::Paren)) {
403 // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
404 let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
405 ast::MetaItemKind::List(list)
476ff2be
SL
406 } else {
407 ast::MetaItemKind::Word
cc61c64b 408 })
223e47cc
LB
409 }
410
e1599b0c 411 /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
9e0c209e 412 fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
9e0c209e 413 match self.parse_unsuffixed_lit() {
dfeec247 414 Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
e1599b0c 415 Err(ref mut err) => err.cancel(),
9e0c209e
SL
416 }
417
418 match self.parse_meta_item() {
dfeec247 419 Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
e1599b0c 420 Err(ref mut err) => err.cancel(),
9e0c209e
SL
421 }
422
dfeec247 423 let found = pprust::token_to_string(&self.token);
532ac7d7 424 let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
dfeec247 425 Err(self.struct_span_err(self.token.span, &msg))
223e47cc
LB
426 }
427}
29967ef6
XL
428
429pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
6a06907d 430 // One of the attributes may either itself be a macro,
fc512014 431 // or expand to macro attributes (`cfg_attr`).
29967ef6 432 attrs.iter().any(|attr| {
cdc7bbd5
XL
433 if attr.is_doc_comment() {
434 return false;
435 }
fc512014 436 attr.ident().map_or(true, |ident| {
6a06907d 437 ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name)
fc512014 438 })
29967ef6
XL
439 })
440}