@@ -360,10 +360,7 @@ impl<'a> Parser<'a> {
360360 let mutbl = self . parse_mutability ( ) ;
361361 self . parse_pat_ident ( BindingMode :: ByRef ( mutbl) ) ?
362362 } else if self . eat_keyword ( kw:: Box ) {
363- // Parse `box pat`
364- let pat = self . parse_pat_with_range_pat ( false , None ) ?;
365- self . sess . gated_spans . gate ( sym:: box_patterns, lo. to ( self . prev_token . span ) ) ;
366- PatKind :: Box ( pat)
363+ self . parse_pat_box ( ) ?
367364 } else if self . check_inline_const ( 0 ) {
368365 // Parse `const pat`
369366 let const_expr = self . parse_const_block ( lo. to ( self . token . span ) , true ) ?;
@@ -915,6 +912,62 @@ impl<'a> Parser<'a> {
915912 Ok ( PatKind :: TupleStruct ( qself, path, fields) )
916913 }
917914
915+ /// Are we sure this could not possibly be the start of a pattern?
916+ ///
917+ /// Currently, this only accounts for tokens that can follow identifiers
918+ /// in patterns, but this can be extended as necessary.
919+ fn isnt_pattern_start ( & self ) -> bool {
920+ [
921+ token:: Eq ,
922+ token:: Colon ,
923+ token:: Comma ,
924+ token:: Semi ,
925+ token:: At ,
926+ token:: OpenDelim ( Delimiter :: Brace ) ,
927+ token:: CloseDelim ( Delimiter :: Brace ) ,
928+ token:: CloseDelim ( Delimiter :: Parenthesis ) ,
929+ ]
930+ . contains ( & self . token . kind )
931+ }
932+
933+ /// Parses `box pat`
934+ fn parse_pat_box ( & mut self ) -> PResult < ' a , PatKind > {
935+ let box_span = self . prev_token . span ;
936+
937+ if self . isnt_pattern_start ( ) {
938+ self . struct_span_err (
939+ self . token . span ,
940+ format ! ( "expected pattern, found {}" , super :: token_descr( & self . token) ) ,
941+ )
942+ . span_note ( box_span, "`box` is a reserved keyword" )
943+ . span_suggestion_verbose (
944+ box_span. shrink_to_lo ( ) ,
945+ "escape `box` to use it as an identifier" ,
946+ "r#" ,
947+ Applicability :: MaybeIncorrect ,
948+ )
949+ . emit ( ) ;
950+
951+ // We cannot use `parse_pat_ident()` since it will complain `box`
952+ // is not an identifier.
953+ let sub = if self . eat ( & token:: At ) {
954+ Some ( self . parse_pat_no_top_alt ( Some ( "binding pattern" ) ) ?)
955+ } else {
956+ None
957+ } ;
958+
959+ Ok ( PatKind :: Ident (
960+ BindingMode :: ByValue ( Mutability :: Not ) ,
961+ Ident :: new ( kw:: Box , box_span) ,
962+ sub,
963+ ) )
964+ } else {
965+ let pat = self . parse_pat_with_range_pat ( false , None ) ?;
966+ self . sess . gated_spans . gate ( sym:: box_patterns, box_span. to ( self . prev_token . span ) ) ;
967+ Ok ( PatKind :: Box ( pat) )
968+ }
969+ }
970+
918971 /// Parses the fields of a struct-like pattern.
919972 fn parse_pat_fields ( & mut self ) -> PResult < ' a , ( Vec < PatField > , bool ) > {
920973 let mut fields = Vec :: new ( ) ;
0 commit comments