Skip to content

Commit 9674c09

Browse files
authored
Rollup merge of #69760 - Centril:parse-expr-improve, r=estebank
Improve expression & attribute parsing This PR includes misc improvements to expression and attribute parsing. 1. Some code simplifications 2. Better recovery for various block forms, e.g. `loop statements }` (missing `{` after `loop`). (See e.g., `block-no-opening-brace.rs` among others for examples.) 3. Added recovery for e.g., `unsafe $b` where `$b` refers to a `block` macro fragment. (See `bad-interpolated-block.rs` for examples.) 4. ^--- These are done so that code sharing in block parsing is increased. 5. Added recovery for e.g., `'label: loop { ... }` (See `labeled-no-colon-expr.rs`.) 6. Added recovery for e.g., `&'lifetime expr` (See `regions-out-of-scope-slice.rs`.) 7. Added recovery for e.g., `fn foo() = expr;` (See `fn-body-eq-expr-semi.rs`.) 8. Simplified attribute parsing code & slightly improved diagnostics. 9. Added recovery for e.g., `Box<('a) + Trait>`. 10. Added recovery for e.g, `if true #[attr] {} else #[attr] {} else #[attr] if true {}`. r? @estebank
2 parents dde2484 + 458383d commit 9674c09

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+926
-401
lines changed

src/librustc_ast/token.rs

+10
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,16 @@ impl Token {
535535
false
536536
}
537537

538+
// Is the token an interpolated block (`$b:block`)?
539+
pub fn is_whole_block(&self) -> bool {
540+
if let Interpolated(ref nt) = self.kind {
541+
if let NtBlock(..) = **nt {
542+
return true;
543+
}
544+
}
545+
false
546+
}
547+
538548
/// Returns `true` if the token is either the `mut` or `const` keyword.
539549
pub fn is_mutability(&self) -> bool {
540550
self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)

src/librustc_parse/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
#![feature(bool_to_option)]
44
#![feature(crate_visibility_modifier)]
5+
#![feature(bindings_after_at)]
56

67
use rustc_ast::ast;
78
use rustc_ast::token::{self, Nonterminal};

src/librustc_parse/parser/attr.rs

+98-133
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Parser, PathStyle, TokenType};
1+
use super::{Parser, PathStyle};
22
use rustc_ast::ast;
33
use rustc_ast::attr;
44
use rustc_ast::token::{self, Nonterminal};
@@ -10,63 +10,65 @@ use rustc_span::{Span, Symbol};
1010
use log::debug;
1111

1212
#[derive(Debug)]
13-
enum InnerAttributeParsePolicy<'a> {
13+
pub(super) enum InnerAttrPolicy<'a> {
1414
Permitted,
15-
NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
15+
Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
1616
}
1717

1818
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
1919
permitted in this context";
2020

21+
pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
22+
reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
23+
saw_doc_comment: false,
24+
prev_attr_sp: None,
25+
};
26+
2127
impl<'a> Parser<'a> {
2228
/// Parses attributes that appear before an item.
2329
pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
2430
let mut attrs: Vec<ast::Attribute> = Vec::new();
2531
let mut just_parsed_doc_comment = false;
2632
loop {
2733
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().map(|a| 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(
34+
if self.check(&token::Pound) {
35+
let inner_error_reason = if just_parsed_doc_comment {
36+
"an inner attribute is not permitted following an outer doc comment"
37+
} else if !attrs.is_empty() {
38+
"an inner attribute is not permitted following an outer attribute"
39+
} else {
40+
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
41+
};
42+
let inner_parse_policy = InnerAttrPolicy::Forbidden {
43+
reason: inner_error_reason,
44+
saw_doc_comment: just_parsed_doc_comment,
45+
prev_attr_sp: attrs.last().map(|a| a.span),
46+
};
47+
let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
48+
attrs.push(attr);
49+
just_parsed_doc_comment = false;
50+
} else if let token::DocComment(s) = self.token.kind {
51+
let attr = self.mk_doc_comment(s);
52+
if attr.style != ast::AttrStyle::Outer {
53+
self.struct_span_err(self.token.span, "expected outer doc comment")
54+
.note(
5255
"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;
56+
`//!` or `/*!`) can only appear before items",
57+
)
58+
.emit();
6059
}
61-
_ => break,
60+
attrs.push(attr);
61+
self.bump();
62+
just_parsed_doc_comment = true;
63+
} else {
64+
break;
6265
}
6366
}
6467
Ok(attrs)
6568
}
6669

6770
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)
71+
attr::mk_doc_comment(comments::doc_comment_style(&s.as_str()), s, self.token.span)
7072
}
7173

7274
/// Matches `attribute = # ! [ meta_item ]`.
@@ -75,96 +77,67 @@ impl<'a> Parser<'a> {
7577
/// attribute.
7678
pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
7779
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-
};
80+
let inner_parse_policy =
81+
if permit_inner { InnerAttrPolicy::Permitted } else { DEFAULT_INNER_ATTR_FORBIDDEN };
8782
self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
8883
}
8984

90-
/// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
85+
/// The same as `parse_attribute`, except it takes in an `InnerAttrPolicy`
9186
/// that prescribes how to handle inner attributes.
9287
fn parse_attribute_with_inner_parse_policy(
9388
&mut self,
94-
inner_parse_policy: InnerAttributeParsePolicy<'_>,
89+
inner_parse_policy: InnerAttrPolicy<'_>,
9590
) -> PResult<'a, ast::Attribute> {
9691
debug!(
9792
"parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
9893
inner_parse_policy, self.token
9994
);
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-
};
95+
let lo = self.token.span;
96+
let (span, item, style) = if self.eat(&token::Pound) {
97+
let style =
98+
if self.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
11599

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 attribute")
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-
}
100+
self.expect(&token::OpenDelim(token::Bracket))?;
101+
let item = self.parse_attr_item()?;
102+
self.expect(&token::CloseDelim(token::Bracket))?;
103+
let attr_sp = lo.to(self.prev_token.span);
155104

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));
105+
// Emit error if inner attribute is encountered and forbidden.
106+
if style == ast::AttrStyle::Inner {
107+
self.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
162108
}
109+
110+
(attr_sp, item, style)
111+
} else {
112+
let token_str = pprust::token_to_string(&self.token);
113+
let msg = &format!("expected `#`, found `{}`", token_str);
114+
return Err(self.struct_span_err(self.token.span, msg));
163115
};
164116

165117
Ok(attr::mk_attr_from_item(style, item, span))
166118
}
167119

120+
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
121+
if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
122+
let prev_attr_note =
123+
if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
124+
125+
let mut diag = self.struct_span_err(attr_sp, reason);
126+
127+
if let Some(prev_attr_sp) = prev_attr_sp {
128+
diag.span_label(attr_sp, "not permitted following an outer attribute")
129+
.span_label(prev_attr_sp, prev_attr_note);
130+
}
131+
132+
diag.note(
133+
"inner attributes, like `#![no_std]`, annotate the item enclosing them, \
134+
and are usually found at the beginning of source files. \
135+
Outer attributes, like `#[test]`, annotate the item following them.",
136+
)
137+
.emit();
138+
}
139+
}
140+
168141
/// Parses an inner part of an attribute (the path and following tokens).
169142
/// The tokens must be either a delimited token stream, or empty token stream,
170143
/// or the "legacy" key-value form.
@@ -200,28 +173,22 @@ impl<'a> Parser<'a> {
200173
crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
201174
let mut attrs: Vec<ast::Attribute> = vec![];
202175
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);
176+
// Only try to parse if it is an inner attribute (has `!`).
177+
if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
178+
let attr = self.parse_attribute(true)?;
179+
assert_eq!(attr.style, ast::AttrStyle::Inner);
180+
attrs.push(attr);
181+
} else if let token::DocComment(s) = self.token.kind {
182+
// We need to get the position of this token before we bump.
183+
let attr = self.mk_doc_comment(s);
184+
if attr.style == ast::AttrStyle::Inner {
212185
attrs.push(attr);
186+
self.bump();
187+
} else {
188+
break;
213189
}
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,
190+
} else {
191+
break;
225192
}
226193
}
227194
Ok(attrs)
@@ -232,12 +199,10 @@ impl<'a> Parser<'a> {
232199
debug!("checking if {:?} is unusuffixed", lit);
233200

234201
if !lit.kind.is_unsuffixed() {
235-
let msg = "suffixed literals are not allowed in attributes";
236-
self.struct_span_err(lit.span, msg)
202+
self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes")
237203
.help(
238-
"instead of using a suffixed literal \
239-
(`1u8`, `1.0f32`, etc.), use an unsuffixed version \
240-
(`1`, `1.0`, etc.)",
204+
"instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
205+
use an unsuffixed version (`1`, `1.0`, etc.)",
241206
)
242207
.emit();
243208
}

0 commit comments

Comments
 (0)