Skip to content

Commit caf888c

Browse files
authored
Rollup merge of rust-lang#127806 - nnethercote:parser-improvements, r=spastorino
Some parser improvements I was looking closely at attribute handling in the parser while debugging some issues relating to rust-lang#124141, and found a few small improvements. ```@spastorino```
2 parents af30f40 + 9c4f3db commit caf888c

File tree

6 files changed

+92
-122
lines changed

6 files changed

+92
-122
lines changed

compiler/rustc_ast/src/token.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -699,8 +699,7 @@ impl Token {
699699
false
700700
}
701701

702-
/// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
703-
/// That is, is this a pre-parsed expression dropped into the token stream
702+
/// Is this a pre-parsed expression dropped into the token stream
704703
/// (which happens while parsing the result of macro expansion)?
705704
pub fn is_whole_expr(&self) -> bool {
706705
if let Interpolated(nt) = &self.kind

compiler/rustc_parse/src/parser/expr.rs

+56-69
Original file line numberDiff line numberDiff line change
@@ -785,23 +785,14 @@ impl<'a> Parser<'a> {
785785
}
786786
};
787787

788-
self.parse_and_disallow_postfix_after_cast(cast_expr)
789-
}
790-
791-
/// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast,
792-
/// then emits an error and returns the newly parsed tree.
793-
/// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
794-
fn parse_and_disallow_postfix_after_cast(
795-
&mut self,
796-
cast_expr: P<Expr>,
797-
) -> PResult<'a, P<Expr>> {
798-
if let ExprKind::Type(_, _) = cast_expr.kind {
799-
panic!("ExprKind::Type must not be parsed");
800-
}
788+
// Try to parse a postfix operator such as `.`, `?`, or index (`[]`)
789+
// after a cast. If one is present, emit an error then return a valid
790+
// parse tree; For something like `&x as T[0]` will be as if it was
791+
// written `((&x) as T)[0]`.
801792

802793
let span = cast_expr.span;
803794

804-
let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?;
795+
let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
805796

806797
// Check if an illegal postfix operator has been added after the cast.
807798
// If the resulting expression is not a cast, it is an illegal postfix operator.
@@ -885,23 +876,63 @@ impl<'a> Parser<'a> {
885876
self.collect_tokens_for_expr(attrs, |this, attrs| {
886877
let base = this.parse_expr_bottom()?;
887878
let span = this.interpolated_or_expr_span(&base);
888-
this.parse_expr_dot_or_call_with(base, span, attrs)
879+
this.parse_expr_dot_or_call_with(attrs, base, span)
889880
})
890881
}
891882

892883
pub(super) fn parse_expr_dot_or_call_with(
893884
&mut self,
894-
e0: P<Expr>,
895-
lo: Span,
896885
mut attrs: ast::AttrVec,
886+
mut e: P<Expr>,
887+
lo: Span,
897888
) -> PResult<'a, P<Expr>> {
898-
// Stitch the list of outer attributes onto the return value.
899-
// A little bit ugly, but the best way given the current code
900-
// structure
901-
let res = ensure_sufficient_stack(
902-
// this expr demonstrates the recursion it guards against
903-
|| self.parse_expr_dot_or_call_with_(e0, lo),
904-
);
889+
let res = ensure_sufficient_stack(|| {
890+
loop {
891+
let has_question =
892+
if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
893+
// We are using noexpect here because we don't expect a `?` directly after
894+
// a `return` which could be suggested otherwise.
895+
self.eat_noexpect(&token::Question)
896+
} else {
897+
self.eat(&token::Question)
898+
};
899+
if has_question {
900+
// `expr?`
901+
e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
902+
continue;
903+
}
904+
let has_dot =
905+
if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
906+
// We are using noexpect here because we don't expect a `.` directly after
907+
// a `return` which could be suggested otherwise.
908+
self.eat_noexpect(&token::Dot)
909+
} else if self.token.kind == TokenKind::RArrow && self.may_recover() {
910+
// Recovery for `expr->suffix`.
911+
self.bump();
912+
let span = self.prev_token.span;
913+
self.dcx().emit_err(errors::ExprRArrowCall { span });
914+
true
915+
} else {
916+
self.eat(&token::Dot)
917+
};
918+
if has_dot {
919+
// expr.f
920+
e = self.parse_dot_suffix_expr(lo, e)?;
921+
continue;
922+
}
923+
if self.expr_is_complete(&e) {
924+
return Ok(e);
925+
}
926+
e = match self.token.kind {
927+
token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
928+
token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
929+
_ => return Ok(e),
930+
}
931+
}
932+
});
933+
934+
// Stitch the list of outer attributes onto the return value. A little
935+
// bit ugly, but the best way given the current code structure.
905936
if attrs.is_empty() {
906937
res
907938
} else {
@@ -915,50 +946,6 @@ impl<'a> Parser<'a> {
915946
}
916947
}
917948

918-
fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
919-
loop {
920-
let has_question =
921-
if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
922-
// we are using noexpect here because we don't expect a `?` directly after a `return`
923-
// which could be suggested otherwise
924-
self.eat_noexpect(&token::Question)
925-
} else {
926-
self.eat(&token::Question)
927-
};
928-
if has_question {
929-
// `expr?`
930-
e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
931-
continue;
932-
}
933-
let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
934-
// we are using noexpect here because we don't expect a `.` directly after a `return`
935-
// which could be suggested otherwise
936-
self.eat_noexpect(&token::Dot)
937-
} else if self.token.kind == TokenKind::RArrow && self.may_recover() {
938-
// Recovery for `expr->suffix`.
939-
self.bump();
940-
let span = self.prev_token.span;
941-
self.dcx().emit_err(errors::ExprRArrowCall { span });
942-
true
943-
} else {
944-
self.eat(&token::Dot)
945-
};
946-
if has_dot {
947-
// expr.f
948-
e = self.parse_dot_suffix_expr(lo, e)?;
949-
continue;
950-
}
951-
if self.expr_is_complete(&e) {
952-
return Ok(e);
953-
}
954-
e = match self.token.kind {
955-
token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
956-
token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
957-
_ => return Ok(e),
958-
}
959-
}
960-
}
961-
962949
pub(super) fn parse_dot_suffix_expr(
963950
&mut self,
964951
lo: Span,
@@ -1388,7 +1375,7 @@ impl<'a> Parser<'a> {
13881375
/// Parses things like parenthesized exprs, macros, `return`, etc.
13891376
///
13901377
/// N.B., this does not parse outer attributes, and is private because it only works
1391-
/// correctly if called from `parse_dot_or_call_expr()`.
1378+
/// correctly if called from `parse_expr_dot_or_call`.
13921379
fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
13931380
maybe_recover_from_interpolated_ty_qpath!(self, true);
13941381

compiler/rustc_parse/src/parser/item.rs

+32-47
Original file line numberDiff line numberDiff line change
@@ -128,56 +128,41 @@ impl<'a> Parser<'a> {
128128
Some(item.into_inner())
129129
});
130130

131-
let item =
132-
self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
133-
let item =
134-
this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode);
135-
Ok((item?, TrailingToken::None))
136-
})?;
137-
138-
Ok(item)
139-
}
140-
141-
fn parse_item_common_(
142-
&mut self,
143-
mut attrs: AttrVec,
144-
mac_allowed: bool,
145-
attrs_allowed: bool,
146-
fn_parse_mode: FnParseMode,
147-
) -> PResult<'a, Option<Item>> {
148-
let lo = self.token.span;
149-
let vis = self.parse_visibility(FollowedByType::No)?;
150-
let mut def = self.parse_defaultness();
151-
let kind = self.parse_item_kind(
152-
&mut attrs,
153-
mac_allowed,
154-
lo,
155-
&vis,
156-
&mut def,
157-
fn_parse_mode,
158-
Case::Sensitive,
159-
)?;
160-
if let Some((ident, kind)) = kind {
161-
self.error_on_unconsumed_default(def, &kind);
162-
let span = lo.to(self.prev_token.span);
163-
let id = DUMMY_NODE_ID;
164-
let item = Item { ident, attrs, id, kind, vis, span, tokens: None };
165-
return Ok(Some(item));
166-
}
131+
self.collect_tokens_trailing_token(attrs, force_collect, |this, mut attrs| {
132+
let lo = this.token.span;
133+
let vis = this.parse_visibility(FollowedByType::No)?;
134+
let mut def = this.parse_defaultness();
135+
let kind = this.parse_item_kind(
136+
&mut attrs,
137+
mac_allowed,
138+
lo,
139+
&vis,
140+
&mut def,
141+
fn_parse_mode,
142+
Case::Sensitive,
143+
)?;
144+
if let Some((ident, kind)) = kind {
145+
this.error_on_unconsumed_default(def, &kind);
146+
let span = lo.to(this.prev_token.span);
147+
let id = DUMMY_NODE_ID;
148+
let item = Item { ident, attrs, id, kind, vis, span, tokens: None };
149+
return Ok((Some(item), TrailingToken::None));
150+
}
167151

168-
// At this point, we have failed to parse an item.
169-
if !matches!(vis.kind, VisibilityKind::Inherited) {
170-
self.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis });
171-
}
152+
// At this point, we have failed to parse an item.
153+
if !matches!(vis.kind, VisibilityKind::Inherited) {
154+
this.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis });
155+
}
172156

173-
if let Defaultness::Default(span) = def {
174-
self.dcx().emit_err(errors::DefaultNotFollowedByItem { span });
175-
}
157+
if let Defaultness::Default(span) = def {
158+
this.dcx().emit_err(errors::DefaultNotFollowedByItem { span });
159+
}
176160

177-
if !attrs_allowed {
178-
self.recover_attrs_no_item(&attrs)?;
179-
}
180-
Ok(None)
161+
if !attrs_allowed {
162+
this.recover_attrs_no_item(&attrs)?;
163+
}
164+
Ok((None, TrailingToken::None))
165+
})
181166
}
182167

183168
/// Error in-case `default` was parsed in an in-appropriate context.

compiler/rustc_parse/src/parser/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ pub enum TrailingToken {
101101
MaybeComma,
102102
}
103103

104-
/// Like `maybe_whole_expr`, but for things other than expressions.
105104
#[macro_export]
106105
macro_rules! maybe_whole {
107106
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {

compiler/rustc_parse/src/parser/pat.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,9 @@ impl<'a> Parser<'a> {
392392
// Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten.
393393
if let Ok(expr) = snapshot
394394
.parse_expr_dot_or_call_with(
395+
AttrVec::new(),
395396
self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr`
396397
pat_span,
397-
AttrVec::new(),
398398
)
399399
.map_err(|err| err.cancel())
400400
{

compiler/rustc_parse/src/parser/stmt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl<'a> Parser<'a> {
164164
};
165165

166166
let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
167-
this.parse_expr_dot_or_call_with(expr, lo, attrs)
167+
this.parse_expr_dot_or_call_with(attrs, expr, lo)
168168
})?;
169169
// `DUMMY_SP` will get overwritten later in this function
170170
Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None))
@@ -206,7 +206,7 @@ impl<'a> Parser<'a> {
206206
// Since none of the above applied, this is an expression statement macro.
207207
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
208208
let e = self.maybe_recover_from_bad_qpath(e)?;
209-
let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?;
209+
let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
210210
let e = self
211211
.parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?;
212212
StmtKind::Expr(e)

0 commit comments

Comments
 (0)