@@ -551,8 +551,8 @@ impl<'a> Parser<'a> {
551
551
// Save the state of the parser before parsing type normally, in case there is a
552
552
// LessThan comparison after this cast.
553
553
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) ,
556
556
Err ( mut type_err) => {
557
557
// Rewind to before attempting to parse the type with generics, to recover
558
558
// from situations like `x as usize < y` in which we first tried to parse
@@ -606,41 +606,63 @@ impl<'a> Parser<'a> {
606
606
)
607
607
. emit ( ) ;
608
608
609
- Ok ( expr)
609
+ expr
610
610
}
611
611
Err ( mut path_err) => {
612
612
// Couldn't parse as a path, return original error and parser state.
613
613
path_err. cancel ( ) ;
614
614
mem:: replace ( self , parser_snapshot_after_type) ;
615
- Err ( type_err)
615
+ return Err ( type_err) ;
616
616
}
617
617
}
618
618
}
619
619
} ;
620
620
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
+ }
625
623
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 {
629
649
let expr_str = self . span_to_snippet ( span) ;
630
650
631
651
let msg = format ! (
632
- "casts followed by {} are not supported " ,
652
+ "casts cannot be followed by {}" ,
633
653
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) ,
640
662
}
641
663
) ;
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" ;
644
666
if let Ok ( expr_str) = expr_str {
645
667
err. span_suggestion (
646
668
span,
0 commit comments