about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser/expr.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-28 14:22:27 +0000
committerbors <bors@rust-lang.org>2024-07-28 14:22:27 +0000
commit48fb66be7a657839bdf8f42ae06fc17893c2d162 (patch)
treefee681aba06a57873e1736b19e78d97a21443dc5 /compiler/rustc_parse/src/parser/expr.rs
parent159524019f6c4ab8908dc297aeea4e5c4d1f2c89 (diff)
parenta973d3f0879c486a8485b99244f1060f69a31a33 (diff)
downloadrust-48fb66be7a657839bdf8f42ae06fc17893c2d162.tar.gz
rust-48fb66be7a657839bdf8f42ae06fc17893c2d162.zip
Auto merge of #17732 - lnicola:sync-from-rust, r=lnicola
minor: sync from downstream
Diffstat (limited to 'compiler/rustc_parse/src/parser/expr.rs')
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs176
1 files changed, 82 insertions, 94 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 4bd20be4171..389a6d11e19 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -5,12 +5,12 @@ use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
     AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
-    SemiColonMode, SeqSep, TokenType, Trailing, TrailingToken,
+    SemiColonMode, SeqSep, TokenType, Trailing,
 };
 
 use crate::errors;
 use crate::maybe_recover_from_interpolated_ty_qpath;
-use ast::mut_visit::{noop_visit_expr, MutVisitor};
+use ast::mut_visit::{self, MutVisitor};
 use ast::token::IdentIsRaw;
 use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
 use core::mem;
@@ -785,23 +785,14 @@ impl<'a> Parser<'a> {
             }
         };
 
-        self.parse_and_disallow_postfix_after_cast(cast_expr)
-    }
-
-    /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast,
-    /// then emits an error and returns the newly parsed tree.
-    /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
-    fn parse_and_disallow_postfix_after_cast(
-        &mut self,
-        cast_expr: P<Expr>,
-    ) -> PResult<'a, P<Expr>> {
-        if let ExprKind::Type(_, _) = cast_expr.kind {
-            panic!("ExprKind::Type must not be parsed");
-        }
+        // Try to parse a postfix operator such as `.`, `?`, or index (`[]`)
+        // after a cast. If one is present, emit an error then return a valid
+        // parse tree; For something like `&x as T[0]` will be as if it was
+        // written `((&x) as T)[0]`.
 
         let span = cast_expr.span;
 
-        let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?;
+        let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
 
         // Check if an illegal postfix operator has been added after the cast.
         // If the resulting expression is not a cast, it is an illegal postfix operator.
@@ -885,23 +876,63 @@ impl<'a> Parser<'a> {
         self.collect_tokens_for_expr(attrs, |this, attrs| {
             let base = this.parse_expr_bottom()?;
             let span = this.interpolated_or_expr_span(&base);
-            this.parse_expr_dot_or_call_with(base, span, attrs)
+            this.parse_expr_dot_or_call_with(attrs, base, span)
         })
     }
 
     pub(super) fn parse_expr_dot_or_call_with(
         &mut self,
-        e0: P<Expr>,
-        lo: Span,
         mut attrs: ast::AttrVec,
+        mut e: P<Expr>,
+        lo: Span,
     ) -> PResult<'a, P<Expr>> {
-        // Stitch the list of outer attributes onto the return value.
-        // A little bit ugly, but the best way given the current code
-        // structure
-        let res = ensure_sufficient_stack(
-            // this expr demonstrates the recursion it guards against
-            || self.parse_expr_dot_or_call_with_(e0, lo),
-        );
+        let res = ensure_sufficient_stack(|| {
+            loop {
+                let has_question =
+                    if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
+                        // We are using noexpect here because we don't expect a `?` directly after
+                        // a `return` which could be suggested otherwise.
+                        self.eat_noexpect(&token::Question)
+                    } else {
+                        self.eat(&token::Question)
+                    };
+                if has_question {
+                    // `expr?`
+                    e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
+                    continue;
+                }
+                let has_dot =
+                    if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
+                        // We are using noexpect here because we don't expect a `.` directly after
+                        // a `return` which could be suggested otherwise.
+                        self.eat_noexpect(&token::Dot)
+                    } else if self.token.kind == TokenKind::RArrow && self.may_recover() {
+                        // Recovery for `expr->suffix`.
+                        self.bump();
+                        let span = self.prev_token.span;
+                        self.dcx().emit_err(errors::ExprRArrowCall { span });
+                        true
+                    } else {
+                        self.eat(&token::Dot)
+                    };
+                if has_dot {
+                    // expr.f
+                    e = self.parse_dot_suffix_expr(lo, e)?;
+                    continue;
+                }
+                if self.expr_is_complete(&e) {
+                    return Ok(e);
+                }
+                e = match self.token.kind {
+                    token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
+                    token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
+                    _ => return Ok(e),
+                }
+            }
+        });
+
+        // Stitch the list of outer attributes onto the return value. A little
+        // bit ugly, but the best way given the current code structure.
         if attrs.is_empty() {
             res
         } else {
@@ -915,50 +946,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
-        loop {
-            let has_question =
-                if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
-                    // we are using noexpect here because we don't expect a `?` directly after a `return`
-                    // which could be suggested otherwise
-                    self.eat_noexpect(&token::Question)
-                } else {
-                    self.eat(&token::Question)
-                };
-            if has_question {
-                // `expr?`
-                e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
-                continue;
-            }
-            let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
-                // we are using noexpect here because we don't expect a `.` directly after a `return`
-                // which could be suggested otherwise
-                self.eat_noexpect(&token::Dot)
-            } else if self.token.kind == TokenKind::RArrow && self.may_recover() {
-                // Recovery for `expr->suffix`.
-                self.bump();
-                let span = self.prev_token.span;
-                self.dcx().emit_err(errors::ExprRArrowCall { span });
-                true
-            } else {
-                self.eat(&token::Dot)
-            };
-            if has_dot {
-                // expr.f
-                e = self.parse_dot_suffix_expr(lo, e)?;
-                continue;
-            }
-            if self.expr_is_complete(&e) {
-                return Ok(e);
-            }
-            e = match self.token.kind {
-                token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
-                token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
-                _ => return Ok(e),
-            }
-        }
-    }
-
     pub(super) fn parse_dot_suffix_expr(
         &mut self,
         lo: Span,
@@ -1388,7 +1375,7 @@ impl<'a> Parser<'a> {
     /// Parses things like parenthesized exprs, macros, `return`, etc.
     ///
     /// N.B., this does not parse outer attributes, and is private because it only works
-    /// correctly if called from `parse_dot_or_call_expr()`.
+    /// correctly if called from `parse_expr_dot_or_call`.
     fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
 
@@ -2487,7 +2474,7 @@ impl<'a> Parser<'a> {
                     id: DUMMY_NODE_ID,
                     is_placeholder: false,
                 },
-                TrailingToken::MaybeComma,
+                this.token == token::Comma,
             ))
         })
     }
@@ -2932,10 +2919,17 @@ impl<'a> Parser<'a> {
     }
 
     pub(crate) fn eat_label(&mut self) -> Option<Label> {
-        self.token.lifetime().map(|ident| {
+        if let Some(ident) = self.token.lifetime() {
+            // Disallow `'fn`, but with a better error message than `expect_lifetime`.
+            if ident.without_first_quote().is_reserved() {
+                self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
+            }
+
             self.bump();
-            Label { ident }
-        })
+            Some(Label { ident })
+        } else {
+            None
+        }
     }
 
     /// Parses a `match ... { ... }` expression (`match` token already eaten).
@@ -3263,7 +3257,7 @@ impl<'a> Parser<'a> {
                     id: DUMMY_NODE_ID,
                     is_placeholder: false,
                 },
-                TrailingToken::None,
+                false,
             ))
         })
     }
@@ -3772,7 +3766,7 @@ impl<'a> Parser<'a> {
                     id: DUMMY_NODE_ID,
                     is_placeholder: false,
                 },
-                TrailingToken::MaybeComma,
+                this.token == token::Comma,
             ))
         })
     }
@@ -3868,18 +3862,12 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, P<Expr>> {
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let res = f(this, attrs)?;
-            let trailing = if this.restrictions.contains(Restrictions::STMT_EXPR)
-                && this.token.kind == token::Semi
-            {
-                TrailingToken::Semi
-            } else if this.token.kind == token::Gt {
-                TrailingToken::Gt
-            } else {
-                // FIXME - pass this through from the place where we know
-                // we need a comma, rather than assuming that `#[attr] expr,`
-                // always captures a trailing comma
-                TrailingToken::MaybeComma
-            };
+            let trailing = (this.restrictions.contains(Restrictions::STMT_EXPR)
+                 && this.token.kind == token::Semi)
+            // FIXME: pass an additional condition through from the place
+            // where we know we need a comma, rather than assuming that
+            // `#[attr] expr,` always captures a trailing comma.
+            || this.token.kind == token::Comma;
             Ok((res, trailing))
         })
     }
@@ -3951,14 +3939,14 @@ impl MutVisitor for CondChecker<'_> {
                 }
             }
             ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
             }
             ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
                 if let None | Some(NotSupportedOr(_)) = self.forbid_let_reason =>
             {
                 let forbid_let_reason = self.forbid_let_reason;
                 self.forbid_let_reason = Some(NotSupportedOr(or_span));
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
             }
             ExprKind::Paren(ref inner)
@@ -3966,7 +3954,7 @@ impl MutVisitor for CondChecker<'_> {
             {
                 let forbid_let_reason = self.forbid_let_reason;
                 self.forbid_let_reason = Some(NotSupportedParentheses(inner.span));
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
             }
             ExprKind::Assign(ref lhs, _, span) => {
@@ -3984,7 +3972,7 @@ impl MutVisitor for CondChecker<'_> {
                 }
                 let comparison = self.comparison;
                 self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() });
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
                 self.missing_let = missing_let;
                 self.comparison = comparison;
@@ -4004,7 +3992,7 @@ impl MutVisitor for CondChecker<'_> {
             | ExprKind::Paren(_) => {
                 let forbid_let_reason = self.forbid_let_reason;
                 self.forbid_let_reason = Some(OtherForbidden);
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
             }
             ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => {