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.
This commit is contained in:
parent
8ba3ca0e6b
commit
940f65782c
3 changed files with 176 additions and 2 deletions
|
|
@ -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>> {
|
||||
|
|
|
|||
63
src/test/ui/parser/issue-35813-postfix-after-cast.rs
Normal file
63
src/test/ui/parser/issue-35813-postfix-after-cast.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// edition:2018
|
||||
#![crate_type = "lib"]
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
// This tests the parser for "x as Y[z]". It errors, but we want to give useful
|
||||
// errors and parse such that further code gives useful errors.
|
||||
pub fn index_after_as_cast() {
|
||||
vec![1, 2, 3] as Vec<i32>[0];
|
||||
//~^ ERROR: casts followed by index operators are not supported
|
||||
}
|
||||
|
||||
pub fn index_after_cast_to_index() {
|
||||
(&[0]) as &[i32][0];
|
||||
//~^ ERROR: casts followed by index operators are not supported
|
||||
}
|
||||
|
||||
// this tests that the precedence for `!x as Y.Z` is still what we expect
|
||||
pub fn precedence() {
|
||||
let x: i32 = &vec![1, 2, 3] as &Vec<i32>[0];
|
||||
//~^ ERROR: casts followed by index operators are not supported
|
||||
}
|
||||
|
||||
pub fn complex() {
|
||||
let _ = format!(
|
||||
"{}",
|
||||
if true { 33 } else { 44 } as i32.max(0)
|
||||
//~^ ERROR: casts followed by method call expressions are not supported
|
||||
);
|
||||
}
|
||||
|
||||
pub fn in_condition() {
|
||||
if 5u64 as i32.max(0) == 0 {
|
||||
//~^ ERROR: casts followed by method call expressions are not supported
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside_block() {
|
||||
let _ = if true {
|
||||
5u64 as u32.max(0) == 0
|
||||
//~^ ERROR: casts followed by method call expressions are not supported
|
||||
} else { false };
|
||||
}
|
||||
|
||||
static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
|
||||
//~^ ERROR: casts followed by index operators are not supported
|
||||
|
||||
pub async fn cast_then_await() {
|
||||
Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>.await;
|
||||
//~^ ERROR: casts followed by awaits are not supported
|
||||
}
|
||||
|
||||
pub async fn noop() {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Foo {
|
||||
pub bar: u32,
|
||||
}
|
||||
|
||||
pub fn struct_field() {
|
||||
Foo::default() as Foo.bar;
|
||||
//~^ ERROR: casts followed by field access expressions are not supported
|
||||
}
|
||||
74
src/test/ui/parser/issue-35813-postfix-after-cast.stderr
Normal file
74
src/test/ui/parser/issue-35813-postfix-after-cast.stderr
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
error: casts followed by index operators are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:9:5
|
||||
|
|
||||
LL | vec![1, 2, 3] as Vec<i32>[0];
|
||||
| -------------------------^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(vec![1, 2, 3] as Vec<i32>)`
|
||||
|
||||
error: casts followed by index operators are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:14:5
|
||||
|
|
||||
LL | (&[0]) as &[i32][0];
|
||||
| ----------------^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `((&[0]) as &[i32])`
|
||||
|
||||
error: casts followed by index operators are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:20:18
|
||||
|
|
||||
LL | let x: i32 = &vec![1, 2, 3] as &Vec<i32>[0];
|
||||
| ---------------------------^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(&vec![1, 2, 3] as &Vec<i32>)`
|
||||
|
||||
error: casts followed by method call expressions are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:33:8
|
||||
|
|
||||
LL | if 5u64 as i32.max(0) == 0 {
|
||||
| -----------^^^^^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(5u64 as i32)`
|
||||
|
||||
error: casts followed by method call expressions are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:40:9
|
||||
|
|
||||
LL | 5u64 as u32.max(0) == 0
|
||||
| -----------^^^^^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(5u64 as u32)`
|
||||
|
||||
error: casts followed by index operators are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:45:24
|
||||
|
|
||||
LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
|
||||
| ------------------^^^^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(&[1,2,3] as &[i32])`
|
||||
|
||||
error: casts followed by awaits are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:49:5
|
||||
|
|
||||
LL | Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>.await;
|
||||
| -----------------------------------------------------^^^^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>)`
|
||||
|
||||
error: casts followed by field access expressions are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:61:5
|
||||
|
|
||||
LL | Foo::default() as Foo.bar;
|
||||
| ---------------------^^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(Foo::default() as Foo)`
|
||||
|
||||
error: casts followed by method call expressions are not supported
|
||||
--> $DIR/issue-35813-postfix-after-cast.rs:27:9
|
||||
|
|
||||
LL | if true { 33 } else { 44 } as i32.max(0)
|
||||
| ---------------------------------^^^^^^^
|
||||
| |
|
||||
| help: try surrounding the expression with parentheses: `(if true { 33 } else { 44 } as i32)`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue