about summary refs log tree commit diff
path: root/src/librustc_parse/parser
diff options
context:
space:
mode:
authorDavid Ross <daboross@daboross.net>2020-02-08 21:34:38 -0800
committerDavid Ross <daboross@daboross.net>2020-02-15 19:50:50 -0800
commit940f65782cc5df7fecad27b38cc25b6d1eeaf2e8 (patch)
treeefb0a542523c63ed8de3ca72ee26e5abe3b8f4e0 /src/librustc_parse/parser
parent8ba3ca0e6bef416ecba3c8ded1f67a953d28600f (diff)
downloadrust-940f65782cc5df7fecad27b38cc25b6d1eeaf2e8.tar.gz
rust-940f65782cc5df7fecad27b38cc25b6d1eeaf2e8.zip
Parse & reject postfix operators after casts
This adds parsing for expressions like 'x as Ty[0]' which will
immediately error out, but still give the rest of the parser a valid
parse tree to continue.
Diffstat (limited to 'src/librustc_parse/parser')
-rw-r--r--src/librustc_parse/parser/expr.rs41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 20b9df0a2d9..d7d3145770c 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -551,7 +551,7 @@ impl<'a> Parser<'a> {
         // Save the state of the parser before parsing type normally, in case there is a
         // LessThan comparison after this cast.
         let parser_snapshot_before_type = self.clone();
-        match self.parse_ty_no_plus() {
+        let type_result = match self.parse_ty_no_plus() {
             Ok(rhs) => Ok(mk_expr(self, rhs)),
             Err(mut type_err) => {
                 // Rewind to before attempting to parse the type with generics, to recover
@@ -616,7 +616,44 @@ impl<'a> Parser<'a> {
                     }
                 }
             }
-        }
+        };
+
+        // Disallow postfix operators such as `.`, `?` or index (`[]`) after casts.
+        // Parses the postfix operator and emits an error.
+        let expr = type_result?;
+        let span = expr.span;
+
+        // The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
+        let with_postfix = self.parse_dot_or_call_expr_with_(expr, span)?;
+        if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
+            let expr_str = self.span_to_snippet(span);
+
+            let msg = format!(
+                "casts followed by {} are not supported",
+                match with_postfix.kind {
+                    ExprKind::Index(_, _) => "index operators",
+                    ExprKind::Try(_) => "try operators",
+                    ExprKind::Field(_, _) => "field access expressions",
+                    ExprKind::MethodCall(_, _) => "method call expressions",
+                    ExprKind::Await(_) => "awaits",
+                    _ => "expressions",
+                }
+            );
+            let mut err = self.struct_span_err(with_postfix.span, &msg);
+            let suggestion = "try surrounding the expression with parentheses";
+            if let Ok(expr_str) = expr_str {
+                err.span_suggestion(
+                    span,
+                    suggestion,
+                    format!("({})", expr_str),
+                    Applicability::MachineApplicable,
+                )
+            } else {
+                err.span_help(span, suggestion)
+            }
+            .emit();
+        };
+        Ok(with_postfix)
     }
 
     fn parse_assoc_op_ascribe(&mut self, lhs: P<Expr>, lhs_span: Span) -> PResult<'a, P<Expr>> {