@@ -551,8 +551,8 @@ impl<'a> Parser<'a> {
551551 // Save the state of the parser before parsing type normally, in case there is a
552552 // LessThan comparison after this cast.
553553 let parser_snapshot_before_type = self . clone ( ) ;
554- let type_result = match self . parse_ty_no_plus ( ) {
555- Ok ( rhs) => Ok ( mk_expr ( self , rhs) ) ,
554+ let cast_expr = match self . parse_ty_no_plus ( ) {
555+ Ok ( rhs) => mk_expr ( self , rhs) ,
556556 Err ( mut type_err) => {
557557 // Rewind to before attempting to parse the type with generics, to recover
558558 // from situations like `x as usize < y` in which we first tried to parse
@@ -606,41 +606,63 @@ impl<'a> Parser<'a> {
606606 )
607607 . emit ( ) ;
608608
609- Ok ( expr)
609+ expr
610610 }
611611 Err ( mut path_err) => {
612612 // Couldn't parse as a path, return original error and parser state.
613613 path_err. cancel ( ) ;
614614 mem:: replace ( self , parser_snapshot_after_type) ;
615- Err ( type_err)
615+ return Err ( type_err) ;
616616 }
617617 }
618618 }
619619 } ;
620620
621- // Disallow postfix operators such as `.`, `?` or index (`[]`) after casts.
622- // Parses the postfix operator and emits an error.
623- let expr = type_result?;
624- let span = expr. span ;
621+ self . parse_and_disallow_postfix_after_cast ( cast_expr)
622+ }
625623
626- // The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
627- let with_postfix = self . parse_dot_or_call_expr_with_ ( expr, span) ?;
628- if !matches ! ( with_postfix. kind, ExprKind :: Cast ( _, _) ) {
624+ /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast,
625+ /// then emits an error and returns the newly parsed tree.
626+ /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
627+ fn parse_and_disallow_postfix_after_cast (
628+ & mut self ,
629+ cast_expr : P < Expr > ,
630+ ) -> PResult < ' a , P < Expr > > {
631+ use std:: collections:: hash_map:: DefaultHasher ;
632+ use std:: hash:: Hasher ;
633+ // Hash the memory location of expr before parsing any following postfix operators.
634+ // This will be compared with the hash of the output expression.
635+ // If they different we can assume we parsed another expression because the existing expression is not reallocated.
636+ let mut before_hasher = DefaultHasher :: new ( ) ;
637+ std:: ptr:: hash ( & * cast_expr, & mut before_hasher) ;
638+ let before_hash = before_hasher. finish ( ) ;
639+ let span = cast_expr. span ;
640+ let with_postfix = self . parse_dot_or_call_expr_with_ ( cast_expr, span) ?;
641+
642+ let mut after_hasher = DefaultHasher :: new ( ) ;
643+ std:: ptr:: hash ( & * with_postfix, & mut after_hasher) ;
644+ let after_hash = after_hasher. finish ( ) ;
645+
646+ // Check if an illegal postfix operator has been added after the cast.
647+ // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator.
648+ if !matches ! ( with_postfix. kind, ExprKind :: Cast ( _, _) ) || after_hash != before_hash {
629649 let expr_str = self . span_to_snippet ( span) ;
630650
631651 let msg = format ! (
632- "casts followed by {} are not supported " ,
652+ "casts cannot be followed by {}" ,
633653 match with_postfix. kind {
634- ExprKind :: Index ( _, _) => "index operators" ,
635- ExprKind :: Try ( _) => "try operators" ,
636- ExprKind :: Field ( _, _) => "field access expressions" ,
637- ExprKind :: MethodCall ( _, _) => "method call expressions" ,
638- ExprKind :: Await ( _) => "awaits" ,
639- _ => "expressions" ,
654+ ExprKind :: Index ( _, _) => "indexing" ,
655+ ExprKind :: Try ( _) => "?" ,
656+ ExprKind :: Field ( _, _) => "a field access" ,
657+ ExprKind :: MethodCall ( _, _) => "a method call" ,
658+ ExprKind :: Call ( _, _) => "a function call" ,
659+ ExprKind :: Await ( _) => "`.await`" ,
660+ ref kind =>
661+ unreachable!( "parse_dot_or_call_expr_with_ shouldn't produce a {:?}" , kind) ,
640662 }
641663 ) ;
642- let mut err = self . struct_span_err ( with_postfix . span , & msg) ;
643- let suggestion = "try surrounding the expression with parentheses" ;
664+ let mut err = self . struct_span_err ( span, & msg) ;
665+ let suggestion = "try surrounding the expression in parentheses" ;
644666 if let Ok ( expr_str) = expr_str {
645667 err. span_suggestion (
646668 span,
0 commit comments