Change:
Summary: Parsing leads to the error: It is currently impossible for a cast expression to have a trailing index expression without surrounding the cast expression by parenthesis. This however seems to be a parser limitation, not a grammar limitation. As currently the macro language guarantees that ty/path expressions can be followed by a "[", this seems like a bug in the parser to me, as it seems to be parsing it as which makes no grammatical sense, compared to parsing it as (value as Type)[index] which should be valid if I read the lexical structure specification correctly.
I think it's parsed correctly, but should get a tailored error message to suggest surrounding the cast with parens.
Considering that a trailing "[" is never valid in the type syntax (otherwise macros break) and the fact that and variants are perfectly legal (even which is another symbol that occurs in type syntax). But if a tailored error message will be made instead, then this should also include other postfix operators like which are currently rejected even though technically being legal by the lexical grammar specification. (another one is the proposed "?" operator)
This is still lacking a tailored error message, and as far as I know no movement has been made here.
Submitted a pull request to fix this!
Thanks!

Discussion:
// 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(); <del> match self.parse_ty_no_plus() { Ok(rhs) => Ok(mk_expr(self, rhs)), </del> <ins> let cast_expr = match self.parse_ty_no_plus() { Ok(rhs) => mk_expr(self, rhs), </ins> 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

) .emit(); <del> Ok(expr) </del> <ins> expr </ins> } 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); <del> Err(type_err) </del> <ins> return Err(type_err); </ins> } } } <del> } </del> <ins> }; 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>> { 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(_, _) | 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 { ExprKind::Index(_, _) => "indexing", ExprKind::Try(_) => "?", ExprKind::Field(_, _) => "a field access", ExprKind::MethodCall(_, _) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_) => "`.await`", _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), } ); 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); } } err.emit(); }; Ok(with_postfix) </ins> } fn parse_assoc_op_ascribe(&mut self, lhs: P<Expr>, lhs_span: Span) -> PResult<'a, P<Expr>> {

<ins> // edition:2018 #![crate_type = "lib"] #![feature(type_ascription)] 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 cannot be followed by indexing vec![1, 2, 3]: Vec<i32>[0]; //~^ ERROR: casts cannot be followed by indexing } pub fn index_after_cast_to_index() { (&[0]) as &[i32][0]; //~^ 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; } 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<i32>[0]; //~^ 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!( "{} 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 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 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 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<u64,u64> { Err(0u64) as Result<u64,u64>?; //~^ ERROR: casts cannot be followed by ? Err(0u64): Result<u64,u64>?; //~^ 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<Box<dyn Future<Output = ()>>>.await; //~^ ERROR: casts cannot be followed by `.await` Box::pin(noop()): Pin<Box<_>>.await; //~^ ERROR: casts cannot be followed by `.await` } pub async fn noop() {} #[derive(Default)] pub struct Foo { pub bar: u32, } pub fn struct_field() { Foo::default() as Foo.bar; //~^ ERROR: cannot be followed by a field access Foo::default(): Foo.bar; //~^ ERROR: cannot be followed by a field access } </ins>

<ins> error: casts cannot be followed by indexing --> $DIR/issue-35813-postfix-after-cast.rs:10:5 | LL |     vec![1, 2, 3] as Vec<i32>[0]; |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(vec![1, 2, 3] as Vec<i32>)` error: casts cannot be followed by indexing --> $DIR/issue-35813-postfix-after-cast.rs:12:5 | LL |     vec![1, 2, 3]: Vec<i32>[0]; |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(vec![1, 2, 3]: Vec<i32>)` 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])` 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 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:63:18 | LL |     let x: i32 = &vec![1, 2, 3] as &Vec<i32>[0]; |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(&vec![1, 2, 3] as &Vec<i32>)` error: casts cannot be followed by a method call --> $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: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: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: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: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: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: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: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:112:5 | LL |     Err(0u64) as Result<u64,u64>?; |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Err(0u64) as Result<u64,u64>)` error: casts cannot be followed by ? --> $DIR/issue-35813-postfix-after-cast.rs:114:5 | LL |     Err(0u64): Result<u64,u64>?; |     ^^^^^^^^^-^^^^^^^^^^^^^^^^ |              | |              help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>` = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information error: casts cannot be followed by a function call --> $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: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:145:5 | LL |     Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>.await; |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try surrounding the expression in parentheses: `(Box::pin(noop()) as Pin<Box<dyn Future<Output = ()>>>)` error: casts cannot be followed by `.await` --> $DIR/issue-35813-postfix-after-cast.rs:148:5 | LL |     Box::pin(noop()): Pin<Box<_>>.await; |     ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^ |                     | |                     help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>` = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information error: casts cannot be followed by a field access --> $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: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: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: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: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:126:15 | LL |     drop_ptr: F(); |               ^^^ only `Fn` traits may use parentheses error: aborting due to 35 previous errors For more information about this error, try `rustc --explain E0214`. </ins>

fn main() { println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>()); <del> //~^ ERROR expected one of </del> <ins> //~^ 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] </ins> }

<del> error: expected one of `!`, `,`, or `::`, found `(` --> $DIR/issue-54516.rs:4:58 </del> <ins> error: casts cannot be followed by a function call --> $DIR/issue-54516.rs:4:20 </ins> | LL |     println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>()); <del> |                            -                             ^ expected one of `!`, `,`, or `::` </del> <ins> |                    ^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ </ins> |                            | |                            help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>` = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information <del> error: aborting due to previous error </del> <ins> error[E0423]: expected value, found module `std::mem` --> $DIR/issue-54516.rs:4:20 | LL |     println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>()); |                    ^^^^^^^^- 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::<BTreeMap<u32, u32>>()); |                            -^^^^^^^ 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`. </ins>

fn main() { let u: usize = std::mem:size_of::<u32>(); <del> //~^ ERROR expected one of </del> <ins> //~^ 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] </ins> }

<del> error: expected one of `!`, `::`, or `;`, found `(` --> $DIR/issue-60933.rs:2:43 </del> <ins> error: casts cannot be followed by a function call --> $DIR/issue-60933.rs:2:20 </ins> | LL |     let u: usize = std::mem:size_of::<u32>(); <del> |                            -              ^ expected one of `!`, `::`, or `;` </del> <ins> |                    ^^^^^^^^-^^^^^^^^^^^^^^ </ins> |                            | |                            help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>` = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information <del> error: aborting due to previous error </del> <ins> error[E0423]: expected value, found module `std::mem` --> $DIR/issue-60933.rs:2:20 | LL |     let u: usize = std::mem:size_of::<u32>(); |                    ^^^^^^^^- 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::<u32>(); |                            -^^^^^^^ 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`. </ins>