From 940f65782cc5df7fecad27b38cc25b6d1eeaf2e8 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 8 Feb 2020 21:34:38 -0800 Subject: [PATCH 01/12] 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. --- src/librustc_parse/parser/expr.rs | 41 +++++++++- .../parser/issue-35813-postfix-after-cast.rs | 63 ++++++++++++++++ .../issue-35813-postfix-after-cast.stderr | 74 +++++++++++++++++++ 3 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/parser/issue-35813-postfix-after-cast.rs create mode 100644 src/test/ui/parser/issue-35813-postfix-after-cast.stderr diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 20b9df0a2d9b6..d7d3145770ca1 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, lhs_span: Span) -> PResult<'a, P> { diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issue-35813-postfix-after-cast.rs new file mode 100644 index 0000000000000..dd608b263ec6c --- /dev/null +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.rs @@ -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[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[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>>.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 +} diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr new file mode 100644 index 0000000000000..9459e076ea0c5 --- /dev/null +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr @@ -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[0]; + | -------------------------^^^ + | | + | help: try surrounding the expression with parentheses: `(vec![1, 2, 3] as Vec)` + +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[0]; + | ---------------------------^^^ + | | + | help: try surrounding the expression with parentheses: `(&vec![1, 2, 3] as &Vec)` + +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>>.await; + | -----------------------------------------------------^^^^^^ + | | + | help: try surrounding the expression with parentheses: `(Box::pin(noop()) as Pin>>)` + +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 + From 5ce9b80c0f93e54bc83f6cb15942ecdce31c3e6a Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 16:12:59 -0800 Subject: [PATCH 02/12] Refactor out error case & apply suggestions. This is almost entirely refactoring and message changing, with the single behavioral change of panicking for unexpected output. --- src/librustc_parse/parser/expr.rs | 62 +++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index d7d3145770ca1..76e4a80878f13 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -551,8 +551,8 @@ 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(); - let type_result = match self.parse_ty_no_plus() { - Ok(rhs) => Ok(mk_expr(self, rhs)), + let cast_expr = match self.parse_ty_no_plus() { + Ok(rhs) => mk_expr(self, rhs), Err(mut type_err) => { // Rewind to before attempting to parse the type with generics, to recover // from situations like `x as usize < y` in which we first tried to parse @@ -606,41 +606,63 @@ impl<'a> Parser<'a> { ) .emit(); - Ok(expr) + expr } Err(mut path_err) => { // Couldn't parse as a path, return original error and parser state. path_err.cancel(); mem::replace(self, parser_snapshot_after_type); - Err(type_err) + return Err(type_err); } } } }; - // 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; + self.parse_and_disallow_postfix_after_cast(cast_expr) + } - // 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(_, _)) { + /// 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, + ) -> PResult<'a, P> { + use std::collections::hash_map::DefaultHasher; + use std::hash::Hasher; + // Hash the memory location of expr before parsing any following postfix operators. + // This will be compared with the hash of the output expression. + // If they different we can assume we parsed another expression because the existing expression is not reallocated. + let mut before_hasher = DefaultHasher::new(); + std::ptr::hash(&*cast_expr, &mut before_hasher); + let before_hash = before_hasher.finish(); + let span = cast_expr.span; + let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?; + + let mut after_hasher = DefaultHasher::new(); + std::ptr::hash(&*with_postfix, &mut after_hasher); + let after_hash = after_hasher.finish(); + + // Check if an illegal postfix operator has been added after the cast. + // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator. + if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) || after_hash != before_hash { let expr_str = self.span_to_snippet(span); let msg = format!( - "casts followed by {} are not supported", + "casts cannot be followed by {}", 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", + ExprKind::Index(_, _) => "indexing", + ExprKind::Try(_) => "?", + ExprKind::Field(_, _) => "a field access", + ExprKind::MethodCall(_, _) => "a method call", + ExprKind::Call(_, _) => "a function call", + ExprKind::Await(_) => "`.await`", + ref kind => + unreachable!("parse_dot_or_call_expr_with_ shouldn't produce a {:?}", kind), } ); - let mut err = self.struct_span_err(with_postfix.span, &msg); - let suggestion = "try surrounding the expression with parentheses"; + let mut err = self.struct_span_err(span, &msg); + let suggestion = "try surrounding the expression in parentheses"; if let Ok(expr_str) = expr_str { err.span_suggestion( span, From 4fc0532269f40c2870936faaebcdd14539613411 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 16:18:20 -0800 Subject: [PATCH 03/12] Type ascription outputs a Type, not Cast Previously this just errored out on all usages of type ascription, which isn't helpful. --- src/librustc_parse/parser/expr.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 76e4a80878f13..645e680d15f48 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -645,7 +645,9 @@ impl<'a> Parser<'a> { // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator. - if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) || after_hash != before_hash { + if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) + || after_hash != before_hash + { let expr_str = self.span_to_snippet(span); let msg = format!( From 0cf204930a2ecaa5f7416602fca6054d4fd44b6b Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 16:18:50 -0800 Subject: [PATCH 04/12] Keep better fix suggestion if type ascription is likely unintended --- src/librustc_parse/parser/expr.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 645e680d15f48..fe5570f26abd5 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -665,17 +665,23 @@ impl<'a> Parser<'a> { ); let mut err = self.struct_span_err(span, &msg); let suggestion = "try surrounding the expression in parentheses"; - if let Ok(expr_str) = expr_str { - err.span_suggestion( - span, - suggestion, - format!("({})", expr_str), - Applicability::MachineApplicable, - ) + // if type ascription is "likely an error", the user will already be getting a useful + // help message, and doesn't need a second. + if self.last_type_ascription.map_or(false, |last_ascription| last_ascription.1) { + self.maybe_annotate_with_ascription(&mut err, false); } else { - err.span_help(span, suggestion) + if let Ok(expr_str) = expr_str { + err.span_suggestion( + span, + suggestion, + format!("({})", expr_str), + Applicability::MachineApplicable, + ); + } else { + err.span_help(span, suggestion); + } } - .emit(); + err.emit(); }; Ok(with_postfix) } From f82ca8b0efa64bc33ed811b34c83a21aeb2950d1 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 16:20:53 -0800 Subject: [PATCH 05/12] Add more error cases to issue 35813 tests --- .../parser/issue-35813-postfix-after-cast.rs | 100 ++++++++-- .../issue-35813-postfix-after-cast.stderr | 183 +++++++++++++----- 2 files changed, 225 insertions(+), 58 deletions(-) diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issue-35813-postfix-after-cast.rs index dd608b263ec6c..0083a475ddfba 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.rs +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.rs @@ -1,5 +1,6 @@ // edition:2018 #![crate_type = "lib"] +#![feature(type_ascription)] use std::future::Future; use std::pin::Pin; @@ -7,47 +8,122 @@ use std::pin::Pin; // errors and parse such that further code gives useful errors. pub fn index_after_as_cast() { vec![1, 2, 3] as Vec[0]; - //~^ ERROR: casts followed by index operators are not supported + //~^ ERROR: casts cannot be followed by indexing + vec![1, 2, 3]: Vec[0]; + //~^ ERROR: casts cannot be followed by indexing } pub fn index_after_cast_to_index() { (&[0]) as &[i32][0]; - //~^ ERROR: casts followed by index operators are not supported + //~^ ERROR: casts cannot be followed by indexing + (&[0i32]): &[i32; 1][0]; + //~^ ERROR: casts cannot be followed by indexing +} + +pub fn cast_after_cast() { + if 5u64 as i32 as u16 == 0u16 { + + } + if 5u64: u64: u64 == 0u64 { + + } + let _ = 5u64: u64: u64 as u8 as i8 == 9i8; + let _ = 0i32: i32: i32; + let _ = 0 as i32: i32; + let _ = 0i32: i32 as i32; + let _ = 0 as i32 as i32; + let _ = 0i32: i32: i32 as u32 as i32; } // 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[0]; - //~^ ERROR: casts followed by index operators are not supported + //~^ ERROR: casts cannot be followed by indexing +} + +pub fn method_calls() { + 0 as i32.max(0); + //~^ ERROR: casts cannot be followed by a method call + 0: i32.max(0); + //~^ ERROR: casts cannot be followed by a method call } pub fn complex() { let _ = format!( - "{}", - if true { 33 } else { 44 } as i32.max(0) - //~^ ERROR: casts followed by method call expressions are not supported + "{} and {}", + if true { 33 } else { 44 } as i32.max(0), + //~^ ERROR: casts cannot be followed by a method call + if true { 33 } else { 44 }: i32.max(0) + //~^ ERROR: casts cannot be followed by a method call ); } pub fn in_condition() { if 5u64 as i32.max(0) == 0 { - //~^ ERROR: casts followed by method call expressions are not supported + //~^ ERROR: casts cannot be followed by a method call + } + if 5u64: u64.max(0) == 0 { + //~^ ERROR: casts cannot be followed by a method call } } pub fn inside_block() { let _ = if true { 5u64 as u32.max(0) == 0 - //~^ ERROR: casts followed by method call expressions are not supported + //~^ ERROR: casts cannot be followed by a method call + } else { false }; + let _ = if true { + 5u64: u64.max(0) == 0 + //~^ ERROR: casts cannot be followed by a method call } else { false }; } static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); -//~^ ERROR: casts followed by index operators are not supported +//~^ ERROR: casts cannot be followed by indexing + +static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); +//~^ ERROR: casts cannot be followed by indexing + + +pub fn cast_then_try() -> Result { + Err(0u64) as Result?; + //~^ ERROR: casts cannot be followed by ? + Err(0u64): Result?; + //~^ ERROR: casts cannot be followed by ? + Ok(1) +} + + +pub fn cast_then_call() { + type F = fn(u8); + // type ascription won't actually do [unique drop fn type] -> fn(u8) casts. + let drop_ptr = drop as fn(u8); + drop as F(); + //~^ ERROR: parenthesized type parameters may only be used with a `Fn` trait [E0214] + drop_ptr: F(); + //~^ ERROR: parenthesized type parameters may only be used with a `Fn` trait [E0214] +} + +pub fn cast_to_fn_should_work() { + let drop_ptr = drop as fn(u8); + drop as fn(u8); + drop_ptr: fn(u8); +} + +pub fn parens_after_cast_error() { + let drop_ptr = drop as fn(u8); + drop as fn(u8)(0); + //~^ ERROR: casts cannot be followed by a function call + drop_ptr: fn(u8)(0); + //~^ ERROR: casts cannot be followed by a function call +} pub async fn cast_then_await() { Box::pin(noop()) as Pin>>.await; - //~^ ERROR: casts followed by awaits are not supported + //~^ ERROR: casts cannot be followed by `.await` + + Box::pin(noop()): Pin>.await; + //~^ ERROR: casts cannot be followed by `.await` } pub async fn noop() {} @@ -59,5 +135,7 @@ pub struct Foo { pub fn struct_field() { Foo::default() as Foo.bar; - //~^ ERROR: casts followed by field access expressions are not supported + //~^ ERROR: cannot be followed by a field access + Foo::default(): Foo.bar; + //~^ ERROR: cannot be followed by a field access } diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr index 9459e076ea0c5..ec6c4eb810737 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr @@ -1,74 +1,163 @@ -error: casts followed by index operators are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:9:5 +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:10:5 | LL | vec![1, 2, 3] as Vec[0]; - | -------------------------^^^ - | | - | help: try surrounding the expression with parentheses: `(vec![1, 2, 3] as Vec)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(vec![1, 2, 3] as Vec)` -error: casts followed by index operators are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:14:5 +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:12:5 + | +LL | vec![1, 2, 3]: Vec[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(vec![1, 2, 3]: Vec)` + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:17:5 | LL | (&[0]) as &[i32][0]; - | ----------------^^^ - | | - | help: try surrounding the expression with parentheses: `((&[0]) as &[i32])` + | ^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `((&[0]) as &[i32])` -error: casts followed by index operators are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:20:18 +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:19:5 + | +LL | (&[0i32]): &[i32; 1][0]; + | ^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `((&[0i32]): &[i32; 1])` + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:40:18 | LL | let x: i32 = &vec![1, 2, 3] as &Vec[0]; - | ---------------------------^^^ - | | - | help: try surrounding the expression with parentheses: `(&vec![1, 2, 3] as &Vec)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&vec![1, 2, 3] as &Vec)` -error: casts followed by method call expressions are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:33:8 +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:45:5 + | +LL | 0 as i32.max(0); + | ^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:47:5 + | +LL | 0: i32.max(0); + | ^^^^^^ help: try surrounding the expression in parentheses: `(0: i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:62:8 | LL | if 5u64 as i32.max(0) == 0 { - | -----------^^^^^^^ - | | - | help: try surrounding the expression with parentheses: `(5u64 as i32)` + | ^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64 as i32)` -error: casts followed by method call expressions are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:40:9 +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:65:8 + | +LL | if 5u64: u64.max(0) == 0 { + | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64: u64)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:72:9 | LL | 5u64 as u32.max(0) == 0 - | -----------^^^^^^^ - | | - | help: try surrounding the expression with parentheses: `(5u64 as u32)` + | ^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64 as u32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:76:9 + | +LL | 5u64: u64.max(0) == 0 + | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64: u64)` -error: casts followed by index operators are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:45:24 +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:81:24 | LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); - | ------------------^^^^^^ - | | - | help: try surrounding the expression with parentheses: `(&[1,2,3] as &[i32])` + | ^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&[1,2,3] as &[i32])` + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:84:25 + | +LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&[1i32,2,3]: &[i32; 3])` + +error: casts cannot be followed by ? + --> $DIR/issue-35813-postfix-after-cast.rs:89:5 + | +LL | Err(0u64) as Result?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Err(0u64) as Result)` + +error: casts cannot be followed by ? + --> $DIR/issue-35813-postfix-after-cast.rs:91:5 + | +LL | Err(0u64): Result?; + | ^^^^^^^^^-^^^^^^^^^^^^^^^^ + | | + | help: maybe write a path separator here: `::` + | + = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` + = note: for more information, see https://github.com/rust-lang/rust/issues/23416 -error: casts followed by awaits are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:49:5 +error: casts cannot be followed by a function call + --> $DIR/issue-35813-postfix-after-cast.rs:115:5 + | +LL | drop as fn(u8)(0); + | ^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(drop as fn(u8))` + +error: casts cannot be followed by a function call + --> $DIR/issue-35813-postfix-after-cast.rs:117:5 + | +LL | drop_ptr: fn(u8)(0); + | ^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(drop_ptr: fn(u8))` + +error: casts cannot be followed by `.await` + --> $DIR/issue-35813-postfix-after-cast.rs:122:5 | LL | Box::pin(noop()) as Pin>>.await; - | -----------------------------------------------------^^^^^^ - | | - | help: try surrounding the expression with parentheses: `(Box::pin(noop()) as Pin>>)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Box::pin(noop()) as Pin>>)` + +error: casts cannot be followed by `.await` + --> $DIR/issue-35813-postfix-after-cast.rs:125:5 + | +LL | Box::pin(noop()): Pin>.await; + | ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^ + | | + | help: maybe write a path separator here: `::` + | + = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` + = note: for more information, see https://github.com/rust-lang/rust/issues/23416 -error: casts followed by field access expressions are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:61:5 +error: casts cannot be followed by a field access + --> $DIR/issue-35813-postfix-after-cast.rs:137:5 | LL | Foo::default() as Foo.bar; - | ---------------------^^^^ - | | - | help: try surrounding the expression with parentheses: `(Foo::default() as Foo)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Foo::default() as Foo)` + +error: casts cannot be followed by a field access + --> $DIR/issue-35813-postfix-after-cast.rs:139:5 + | +LL | Foo::default(): Foo.bar; + | ^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Foo::default(): Foo)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:54:9 + | +LL | if true { 33 } else { 44 } as i32.max(0), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(if true { 33 } else { 44 } as i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:56:9 + | +LL | if true { 33 } else { 44 }: i32.max(0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(if true { 33 } else { 44 }: i32)` + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/issue-35813-postfix-after-cast.rs:101:13 + | +LL | drop as F(); + | ^^^ only `Fn` traits may use parentheses -error: casts followed by method call expressions are not supported - --> $DIR/issue-35813-postfix-after-cast.rs:27:9 +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/issue-35813-postfix-after-cast.rs:103:15 | -LL | if true { 33 } else { 44 } as i32.max(0) - | ---------------------------------^^^^^^^ - | | - | help: try surrounding the expression with parentheses: `(if true { 33 } else { 44 } as i32)` +LL | drop_ptr: F(); + | ^^^ only `Fn` traits may use parentheses -error: aborting due to 9 previous errors +error: aborting due to 25 previous errors +For more information about this error, try `rustc --explain E0214`. From 5dd646435ba882574e677acf58113880a6570949 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 16:21:59 -0800 Subject: [PATCH 06/12] Fix related type ascription tests. --- src/test/ui/type/ascription/issue-54516.rs | 4 ++- .../ui/type/ascription/issue-54516.stderr | 26 ++++++++++++++++--- src/test/ui/type/ascription/issue-60933.rs | 4 ++- .../ui/type/ascription/issue-60933.stderr | 26 ++++++++++++++++--- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/test/ui/type/ascription/issue-54516.rs b/src/test/ui/type/ascription/issue-54516.rs index b53bfe5df03f3..8d6fd2abb6d5f 100644 --- a/src/test/ui/type/ascription/issue-54516.rs +++ b/src/test/ui/type/ascription/issue-54516.rs @@ -2,5 +2,7 @@ use std::collections::BTreeMap; fn main() { println!("{}", std::mem:size_of::>()); - //~^ ERROR expected one of + //~^ ERROR casts cannot be followed by a function call + //~| ERROR expected value, found module `std::mem` [E0423] + //~| ERROR cannot find type `size_of` in this scope [E0412] } diff --git a/src/test/ui/type/ascription/issue-54516.stderr b/src/test/ui/type/ascription/issue-54516.stderr index 7127f67cd7dde..fdf35700ef94c 100644 --- a/src/test/ui/type/ascription/issue-54516.stderr +++ b/src/test/ui/type/ascription/issue-54516.stderr @@ -1,13 +1,31 @@ -error: expected one of `!`, `,`, or `::`, found `(` - --> $DIR/issue-54516.rs:4:58 +error: casts cannot be followed by a function call + --> $DIR/issue-54516.rs:4:20 | LL | println!("{}", std::mem:size_of::>()); - | - ^ expected one of `!`, `,`, or `::` + | ^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` = note: see issue #23416 for more information -error: aborting due to previous error +error[E0423]: expected value, found module `std::mem` + --> $DIR/issue-54516.rs:4:20 + | +LL | println!("{}", std::mem:size_of::>()); + | ^^^^^^^^- help: maybe you meant to write a path separator here: `::` + | | + | not a value + +error[E0412]: cannot find type `size_of` in this scope + --> $DIR/issue-54516.rs:4:29 + | +LL | println!("{}", std::mem:size_of::>()); + | -^^^^^^^ not found in this scope + | | + | help: maybe you meant to write a path separator here: `::` + +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0412, E0423. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/type/ascription/issue-60933.rs b/src/test/ui/type/ascription/issue-60933.rs index 8fb06c887bd3e..bcf9f88cb414b 100644 --- a/src/test/ui/type/ascription/issue-60933.rs +++ b/src/test/ui/type/ascription/issue-60933.rs @@ -1,4 +1,6 @@ fn main() { let u: usize = std::mem:size_of::(); - //~^ ERROR expected one of + //~^ ERROR casts cannot be followed by a function call + //~| ERROR expected value, found module `std::mem` [E0423] + //~| ERROR cannot find type `size_of` in this scope [E0412] } diff --git a/src/test/ui/type/ascription/issue-60933.stderr b/src/test/ui/type/ascription/issue-60933.stderr index 7130767b6c6f3..cd9ae8f49f4f1 100644 --- a/src/test/ui/type/ascription/issue-60933.stderr +++ b/src/test/ui/type/ascription/issue-60933.stderr @@ -1,13 +1,31 @@ -error: expected one of `!`, `::`, or `;`, found `(` - --> $DIR/issue-60933.rs:2:43 +error: casts cannot be followed by a function call + --> $DIR/issue-60933.rs:2:20 | LL | let u: usize = std::mem:size_of::(); - | - ^ expected one of `!`, `::`, or `;` + | ^^^^^^^^-^^^^^^^^^^^^^^ | | | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` = note: see issue #23416 for more information -error: aborting due to previous error +error[E0423]: expected value, found module `std::mem` + --> $DIR/issue-60933.rs:2:20 + | +LL | let u: usize = std::mem:size_of::(); + | ^^^^^^^^- help: maybe you meant to write a path separator here: `::` + | | + | not a value + +error[E0412]: cannot find type `size_of` in this scope + --> $DIR/issue-60933.rs:2:29 + | +LL | let u: usize = std::mem:size_of::(); + | -^^^^^^^ not found in this scope + | | + | help: maybe you meant to write a path separator here: `::` + +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0412, E0423. +For more information about an error, try `rustc --explain E0412`. From e3eefe266756449ebe3b2c1bb177f0130569b3b2 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 17:09:42 -0800 Subject: [PATCH 07/12] Remove extra debug print in unreachable! --- src/librustc_parse/parser/expr.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index fe5570f26abd5..3d0f746d3955c 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -659,8 +659,7 @@ impl<'a> Parser<'a> { ExprKind::MethodCall(_, _) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_) => "`.await`", - ref kind => - unreachable!("parse_dot_or_call_expr_with_ shouldn't produce a {:?}", kind), + _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), } ); let mut err = self.struct_span_err(span, &msg); From c2d7ffb8a9906f5c7b6a1cf6a739cf4d7d732c2b Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 17:17:09 -0800 Subject: [PATCH 08/12] Remove trailing whitespace --- src/test/ui/parser/issue-35813-postfix-after-cast.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issue-35813-postfix-after-cast.rs index 0083a475ddfba..d04a092e93b00 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.rs +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.rs @@ -22,10 +22,10 @@ pub fn index_after_cast_to_index() { pub fn cast_after_cast() { if 5u64 as i32 as u16 == 0u16 { - + } if 5u64: u64: u64 == 0u64 { - + } let _ = 5u64: u64: u64 as u8 as i8 == 9i8; let _ = 0i32: i32: i32; @@ -107,7 +107,7 @@ pub fn cast_then_call() { pub fn cast_to_fn_should_work() { let drop_ptr = drop as fn(u8); drop as fn(u8); - drop_ptr: fn(u8); + drop_ptr: fn(u8); } pub fn parens_after_cast_error() { From 8ef3da0858c5a76fd1756b9efcf82eeb9491fb64 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 15 Feb 2020 22:08:29 -0800 Subject: [PATCH 09/12] Fix test stderr after rebasing on master. --- src/test/ui/parser/issue-35813-postfix-after-cast.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr index ec6c4eb810737..f96000ea0aa4d 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr @@ -91,7 +91,7 @@ LL | Err(0u64): Result?; | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` - = note: for more information, see https://github.com/rust-lang/rust/issues/23416 + = note: see issue #23416 for more information error: casts cannot be followed by a function call --> $DIR/issue-35813-postfix-after-cast.rs:115:5 @@ -120,7 +120,7 @@ LL | Box::pin(noop()): Pin>.await; | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` - = note: for more information, see https://github.com/rust-lang/rust/issues/23416 + = note: see issue #23416 for more information error: casts cannot be followed by a field access --> $DIR/issue-35813-postfix-after-cast.rs:137:5 From fa1f547f82d66f986af2c33220199b042fcb5f99 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 22 Feb 2020 11:36:09 -0800 Subject: [PATCH 10/12] Add more double cast + method call tests --- .../parser/issue-35813-postfix-after-cast.rs | 23 ++++ .../issue-35813-postfix-after-cast.stderr | 104 ++++++++++++++---- 2 files changed, 105 insertions(+), 22 deletions(-) diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issue-35813-postfix-after-cast.rs index d04a092e93b00..5c6e0ce5024d9 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.rs +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.rs @@ -35,6 +35,29 @@ pub fn cast_after_cast() { let _ = 0i32: i32: i32 as u32 as i32; } +pub fn cast_cast_method_call() { + let _ = 0i32: i32: i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32: i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32 as i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32 as i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32: i32 as u32 as i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32.count_ones(): u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32.count_ones(): u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32.count_ones() as u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32.count_ones() as u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32: i32.count_ones() as u32 as i32; + //~^ ERROR: casts cannot be followed by a method call +} + // 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[0]; diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr index f96000ea0aa4d..42b614edf7638 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr @@ -22,68 +22,128 @@ error: casts cannot be followed by indexing LL | (&[0i32]): &[i32; 1][0]; | ^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `((&[0i32]): &[i32; 1])` +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:39:13 + | +LL | let _ = 0i32: i32: i32.count_ones(); + | ^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32: i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:41:13 + | +LL | let _ = 0 as i32: i32.count_ones(); + | ^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32: i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:43:13 + | +LL | let _ = 0i32: i32 as i32.count_ones(); + | ^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32 as i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:45:13 + | +LL | let _ = 0 as i32 as i32.count_ones(); + | ^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32 as i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:47:13 + | +LL | let _ = 0i32: i32: i32 as u32 as i32.count_ones(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32: i32 as u32 as i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:49:13 + | +LL | let _ = 0i32: i32.count_ones(): u32; + | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:51:13 + | +LL | let _ = 0 as i32.count_ones(): u32; + | ^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:53:13 + | +LL | let _ = 0i32: i32.count_ones() as u32; + | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:55:13 + | +LL | let _ = 0 as i32.count_ones() as u32; + | ^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32)` + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:57:13 + | +LL | let _ = 0i32: i32: i32.count_ones() as u32 as i32; + | ^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32: i32)` + error: casts cannot be followed by indexing - --> $DIR/issue-35813-postfix-after-cast.rs:40:18 + --> $DIR/issue-35813-postfix-after-cast.rs:63:18 | LL | let x: i32 = &vec![1, 2, 3] as &Vec[0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&vec![1, 2, 3] as &Vec)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:45:5 + --> $DIR/issue-35813-postfix-after-cast.rs:68:5 | LL | 0 as i32.max(0); | ^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:47:5 + --> $DIR/issue-35813-postfix-after-cast.rs:70:5 | LL | 0: i32.max(0); | ^^^^^^ help: try surrounding the expression in parentheses: `(0: i32)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:62:8 + --> $DIR/issue-35813-postfix-after-cast.rs:85:8 | LL | if 5u64 as i32.max(0) == 0 { | ^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64 as i32)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:65:8 + --> $DIR/issue-35813-postfix-after-cast.rs:88:8 | LL | if 5u64: u64.max(0) == 0 { | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64: u64)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:72:9 + --> $DIR/issue-35813-postfix-after-cast.rs:95:9 | LL | 5u64 as u32.max(0) == 0 | ^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64 as u32)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:76:9 + --> $DIR/issue-35813-postfix-after-cast.rs:99:9 | LL | 5u64: u64.max(0) == 0 | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64: u64)` error: casts cannot be followed by indexing - --> $DIR/issue-35813-postfix-after-cast.rs:81:24 + --> $DIR/issue-35813-postfix-after-cast.rs:104:24 | LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); | ^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&[1,2,3] as &[i32])` error: casts cannot be followed by indexing - --> $DIR/issue-35813-postfix-after-cast.rs:84:25 + --> $DIR/issue-35813-postfix-after-cast.rs:107:25 | LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); | ^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&[1i32,2,3]: &[i32; 3])` error: casts cannot be followed by ? - --> $DIR/issue-35813-postfix-after-cast.rs:89:5 + --> $DIR/issue-35813-postfix-after-cast.rs:112:5 | LL | Err(0u64) as Result?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Err(0u64) as Result)` error: casts cannot be followed by ? - --> $DIR/issue-35813-postfix-after-cast.rs:91:5 + --> $DIR/issue-35813-postfix-after-cast.rs:114:5 | LL | Err(0u64): Result?; | ^^^^^^^^^-^^^^^^^^^^^^^^^^ @@ -94,25 +154,25 @@ LL | Err(0u64): Result?; = note: see issue #23416 for more information error: casts cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:115:5 + --> $DIR/issue-35813-postfix-after-cast.rs:138:5 | LL | drop as fn(u8)(0); | ^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(drop as fn(u8))` error: casts cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:117:5 + --> $DIR/issue-35813-postfix-after-cast.rs:140:5 | LL | drop_ptr: fn(u8)(0); | ^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(drop_ptr: fn(u8))` error: casts cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:122:5 + --> $DIR/issue-35813-postfix-after-cast.rs:145:5 | LL | Box::pin(noop()) as Pin>>.await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Box::pin(noop()) as Pin>>)` error: casts cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:125:5 + --> $DIR/issue-35813-postfix-after-cast.rs:148:5 | LL | Box::pin(noop()): Pin>.await; | ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^ @@ -123,41 +183,41 @@ LL | Box::pin(noop()): Pin>.await; = note: see issue #23416 for more information error: casts cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:137:5 + --> $DIR/issue-35813-postfix-after-cast.rs:160:5 | LL | Foo::default() as Foo.bar; | ^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Foo::default() as Foo)` error: casts cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:139:5 + --> $DIR/issue-35813-postfix-after-cast.rs:162:5 | LL | Foo::default(): Foo.bar; | ^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Foo::default(): Foo)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:54:9 + --> $DIR/issue-35813-postfix-after-cast.rs:77:9 | LL | if true { 33 } else { 44 } as i32.max(0), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(if true { 33 } else { 44 } as i32)` error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:56:9 + --> $DIR/issue-35813-postfix-after-cast.rs:79:9 | LL | if true { 33 } else { 44 }: i32.max(0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(if true { 33 } else { 44 }: i32)` error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:101:13 + --> $DIR/issue-35813-postfix-after-cast.rs:124:13 | LL | drop as F(); | ^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:103:15 + --> $DIR/issue-35813-postfix-after-cast.rs:126:15 | LL | drop_ptr: F(); | ^^^ only `Fn` traits may use parentheses -error: aborting due to 25 previous errors +error: aborting due to 35 previous errors For more information about this error, try `rustc --explain E0214`. From f434c6e636eda6c6c4fe167eee5b2549f8524ec7 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 22 Feb 2020 12:33:06 -0800 Subject: [PATCH 11/12] Use multipart suggestion This is a modified version of estebank's suggestion, with a bit of extra cleanup now that we don't need the different cases for if we can turn a span into a string or not. --- src/librustc_parse/parser/expr.rs | 22 +- .../parser/issue-35813-postfix-after-cast.rs | 7 + .../issue-35813-postfix-after-cast.stderr | 275 ++++++++++++++---- 3 files changed, 238 insertions(+), 66 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 3d0f746d3955c..12729019e9bdc 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -648,8 +648,6 @@ impl<'a> Parser<'a> { if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) || after_hash != before_hash { - let expr_str = self.span_to_snippet(span); - let msg = format!( "casts cannot be followed by {}", match with_postfix.kind { @@ -663,22 +661,20 @@ impl<'a> Parser<'a> { } ); let mut err = self.struct_span_err(span, &msg); - let suggestion = "try surrounding the expression in parentheses"; // if type ascription is "likely an error", the user will already be getting a useful // help message, and doesn't need a second. if self.last_type_ascription.map_or(false, |last_ascription| last_ascription.1) { self.maybe_annotate_with_ascription(&mut err, false); } else { - if let Ok(expr_str) = expr_str { - err.span_suggestion( - span, - suggestion, - format!("({})", expr_str), - Applicability::MachineApplicable, - ); - } else { - err.span_help(span, suggestion); - } + let suggestions = vec![ + (span.shrink_to_lo(), "(".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ]; + err.multipart_suggestion( + "try surrounding the expression in parentheses", + suggestions, + Applicability::MachineApplicable, + ); } err.emit(); }; diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issue-35813-postfix-after-cast.rs index 5c6e0ce5024d9..e725aa5d73d1f 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.rs +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.rs @@ -58,6 +58,13 @@ pub fn cast_cast_method_call() { //~^ ERROR: casts cannot be followed by a method call } +pub fn multiline_error() { + let _ = 0 + as i32 + .count_ones(); + //~^^^ ERROR: casts cannot be followed by a method call +} + // 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[0]; diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr index 42b614edf7638..255e9f409218b 100644 --- a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr @@ -2,148 +2,282 @@ error: casts cannot be followed by indexing --> $DIR/issue-35813-postfix-after-cast.rs:10:5 | LL | vec![1, 2, 3] as Vec[0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(vec![1, 2, 3] as Vec)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (vec![1, 2, 3] as Vec)[0]; + | ^ ^ error: casts cannot be followed by indexing --> $DIR/issue-35813-postfix-after-cast.rs:12:5 | LL | vec![1, 2, 3]: Vec[0]; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(vec![1, 2, 3]: Vec)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (vec![1, 2, 3]: Vec)[0]; + | ^ ^ error: casts cannot be followed by indexing --> $DIR/issue-35813-postfix-after-cast.rs:17:5 | LL | (&[0]) as &[i32][0]; - | ^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `((&[0]) as &[i32])` + | ^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | ((&[0]) as &[i32])[0]; + | ^ ^ error: casts cannot be followed by indexing --> $DIR/issue-35813-postfix-after-cast.rs:19:5 | LL | (&[0i32]): &[i32; 1][0]; - | ^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `((&[0i32]): &[i32; 1])` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | ((&[0i32]): &[i32; 1])[0]; + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:39:13 | LL | let _ = 0i32: i32: i32.count_ones(); - | ^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32: i32)` + | ^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32: i32).count_ones(); + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:41:13 | LL | let _ = 0 as i32: i32.count_ones(); - | ^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32: i32)` + | ^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32: i32).count_ones(); + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:43:13 | LL | let _ = 0i32: i32 as i32.count_ones(); - | ^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32 as i32)` + | ^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32 as i32).count_ones(); + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:45:13 | LL | let _ = 0 as i32 as i32.count_ones(); - | ^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32 as i32)` + | ^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32 as i32).count_ones(); + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:47:13 | LL | let _ = 0i32: i32: i32 as u32 as i32.count_ones(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32: i32 as u32 as i32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32: i32 as u32 as i32).count_ones(); + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:49:13 | LL | let _ = 0i32: i32.count_ones(): u32; - | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32)` + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32).count_ones(): u32; + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:51:13 | LL | let _ = 0 as i32.count_ones(): u32; - | ^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32)` + | ^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32).count_ones(): u32; + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:53:13 | LL | let _ = 0i32: i32.count_ones() as u32; - | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32)` + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32).count_ones() as u32; + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:55:13 | LL | let _ = 0 as i32.count_ones() as u32; - | ^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32)` + | ^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32).count_ones() as u32; + | ^ ^ error: casts cannot be followed by a method call --> $DIR/issue-35813-postfix-after-cast.rs:57:13 | LL | let _ = 0i32: i32: i32.count_ones() as u32 as i32; - | ^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(0i32: i32: i32)` + | ^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32: i32).count_ones() as u32 as i32; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:62:13 + | +LL | let _ = 0 + | _____________^ +LL | | as i32 + | |______________^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 +LL | as i32) + | error: casts cannot be followed by indexing - --> $DIR/issue-35813-postfix-after-cast.rs:63:18 + --> $DIR/issue-35813-postfix-after-cast.rs:70:18 | LL | let x: i32 = &vec![1, 2, 3] as &Vec[0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&vec![1, 2, 3] as &Vec)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let x: i32 = (&vec![1, 2, 3] as &Vec)[0]; + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:68:5 + --> $DIR/issue-35813-postfix-after-cast.rs:75:5 | LL | 0 as i32.max(0); - | ^^^^^^^^ help: try surrounding the expression in parentheses: `(0 as i32)` + | ^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (0 as i32).max(0); + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:70:5 + --> $DIR/issue-35813-postfix-after-cast.rs:77:5 | LL | 0: i32.max(0); - | ^^^^^^ help: try surrounding the expression in parentheses: `(0: i32)` + | ^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (0: i32).max(0); + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:85:8 + --> $DIR/issue-35813-postfix-after-cast.rs:92:8 | LL | if 5u64 as i32.max(0) == 0 { - | ^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64 as i32)` + | ^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | if (5u64 as i32).max(0) == 0 { + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:88:8 + --> $DIR/issue-35813-postfix-after-cast.rs:95:8 | LL | if 5u64: u64.max(0) == 0 { - | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64: u64)` + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | if (5u64: u64).max(0) == 0 { + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:95:9 + --> $DIR/issue-35813-postfix-after-cast.rs:102:9 | LL | 5u64 as u32.max(0) == 0 - | ^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64 as u32)` + | ^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (5u64 as u32).max(0) == 0 + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:99:9 + --> $DIR/issue-35813-postfix-after-cast.rs:106:9 | LL | 5u64: u64.max(0) == 0 - | ^^^^^^^^^ help: try surrounding the expression in parentheses: `(5u64: u64)` + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (5u64: u64).max(0) == 0 + | ^ ^ error: casts cannot be followed by indexing - --> $DIR/issue-35813-postfix-after-cast.rs:104:24 + --> $DIR/issue-35813-postfix-after-cast.rs:111:24 | LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); - | ^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&[1,2,3] as &[i32])` + | ^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]); + | ^ ^ error: casts cannot be followed by indexing - --> $DIR/issue-35813-postfix-after-cast.rs:107:25 + --> $DIR/issue-35813-postfix-after-cast.rs:114:25 | LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&[1i32,2,3]: &[i32; 3])` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | static bar2: &[i32] = &((&[1i32,2,3]: &[i32; 3])[0..1]); + | ^ ^ error: casts cannot be followed by ? - --> $DIR/issue-35813-postfix-after-cast.rs:112:5 + --> $DIR/issue-35813-postfix-after-cast.rs:119:5 | LL | Err(0u64) as Result?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Err(0u64) as Result)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Err(0u64) as Result)?; + | ^ ^ error: casts cannot be followed by ? - --> $DIR/issue-35813-postfix-after-cast.rs:114:5 + --> $DIR/issue-35813-postfix-after-cast.rs:121:5 | LL | Err(0u64): Result?; | ^^^^^^^^^-^^^^^^^^^^^^^^^^ @@ -154,25 +288,40 @@ LL | Err(0u64): Result?; = note: see issue #23416 for more information error: casts cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:138:5 + --> $DIR/issue-35813-postfix-after-cast.rs:145:5 | LL | drop as fn(u8)(0); - | ^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(drop as fn(u8))` + | ^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (drop as fn(u8))(0); + | ^ ^ error: casts cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:140:5 + --> $DIR/issue-35813-postfix-after-cast.rs:147:5 | LL | drop_ptr: fn(u8)(0); - | ^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(drop_ptr: fn(u8))` + | ^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (drop_ptr: fn(u8))(0); + | ^ ^ error: casts cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:145:5 + --> $DIR/issue-35813-postfix-after-cast.rs:152:5 | LL | Box::pin(noop()) as Pin>>.await; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Box::pin(noop()) as Pin>>)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Box::pin(noop()) as Pin>>).await; + | ^ ^ error: casts cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:148:5 + --> $DIR/issue-35813-postfix-after-cast.rs:155:5 | LL | Box::pin(noop()): Pin>.await; | ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^ @@ -183,41 +332,61 @@ LL | Box::pin(noop()): Pin>.await; = note: see issue #23416 for more information error: casts cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:160:5 + --> $DIR/issue-35813-postfix-after-cast.rs:167:5 | LL | Foo::default() as Foo.bar; - | ^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Foo::default() as Foo)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Foo::default() as Foo).bar; + | ^ ^ error: casts cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:162:5 + --> $DIR/issue-35813-postfix-after-cast.rs:169:5 | LL | Foo::default(): Foo.bar; - | ^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Foo::default(): Foo)` + | ^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Foo::default(): Foo).bar; + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:77:9 + --> $DIR/issue-35813-postfix-after-cast.rs:84:9 | LL | if true { 33 } else { 44 } as i32.max(0), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(if true { 33 } else { 44 } as i32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (if true { 33 } else { 44 } as i32).max(0), + | ^ ^ error: casts cannot be followed by a method call - --> $DIR/issue-35813-postfix-after-cast.rs:79:9 + --> $DIR/issue-35813-postfix-after-cast.rs:86:9 | LL | if true { 33 } else { 44 }: i32.max(0) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(if true { 33 } else { 44 }: i32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (if true { 33 } else { 44 }: i32).max(0) + | ^ ^ error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:124:13 + --> $DIR/issue-35813-postfix-after-cast.rs:131:13 | LL | drop as F(); | ^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:126:15 + --> $DIR/issue-35813-postfix-after-cast.rs:133:15 | LL | drop_ptr: F(); | ^^^ only `Fn` traits may use parentheses -error: aborting due to 35 previous errors +error: aborting due to 36 previous errors For more information about this error, try `rustc --explain E0214`. From 453c5051476fab4d09f6d16bdbf37043c5c26a27 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 24 Feb 2020 22:11:15 -0800 Subject: [PATCH 12/12] Replace ptr hashing with ptr casting Implementes suggeseted changes by Centril. This checks whether the memory location of the cast remains the same after atttempting to parse a postfix operator after a cast has been parsed. If the address is not the same, an illegal postfix operator was parsed. Previously the code generated a hash of the pointer, which was overly complex and inefficent. Casting the pointers and comparing them is simpler and more effcient. --- src/librustc_parse/parser/expr.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 12729019e9bdc..36ed075cebd2f 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -628,26 +628,17 @@ impl<'a> Parser<'a> { &mut self, cast_expr: P, ) -> PResult<'a, P> { - use std::collections::hash_map::DefaultHasher; - use std::hash::Hasher; - // Hash the memory location of expr before parsing any following postfix operators. - // This will be compared with the hash of the output expression. + // Save the memory location of expr before parsing any following postfix operators. + // This will be compared with the memory location of the output expression. // If they different we can assume we parsed another expression because the existing expression is not reallocated. - let mut before_hasher = DefaultHasher::new(); - std::ptr::hash(&*cast_expr, &mut before_hasher); - let before_hash = before_hasher.finish(); + let addr_before = &*cast_expr as *const _ as usize; let span = cast_expr.span; let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?; - - let mut after_hasher = DefaultHasher::new(); - std::ptr::hash(&*with_postfix, &mut after_hasher); - let after_hash = after_hasher.finish(); + let changed = addr_before != &*with_postfix as *const _ as usize; // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator. - if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) - || after_hash != before_hash - { + if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) || changed { let msg = format!( "casts cannot be followed by {}", match with_postfix.kind { @@ -661,7 +652,7 @@ impl<'a> Parser<'a> { } ); let mut err = self.struct_span_err(span, &msg); - // if type ascription is "likely an error", the user will already be getting a useful + // If type ascription is "likely an error", the user will already be getting a useful // help message, and doesn't need a second. if self.last_type_ascription.map_or(false, |last_ascription| last_ascription.1) { self.maybe_annotate_with_ascription(&mut err, false);