@@ -250,6 +250,8 @@ pub struct Parser<'a> {
250
250
desugar_doc_comments : bool ,
251
251
/// Whether we should configure out of line modules as we parse.
252
252
pub cfg_mods : bool ,
253
+ /// Whether we should prevent recovery from parsing areas (during backtracking).
254
+ prevent_recovery : bool ,
253
255
}
254
256
255
257
@@ -569,6 +571,7 @@ impl<'a> Parser<'a> {
569
571
} ,
570
572
desugar_doc_comments,
571
573
cfg_mods : true ,
574
+ prevent_recovery : false ,
572
575
} ;
573
576
574
577
let tok = parser. next_tok ( ) ;
@@ -1111,6 +1114,9 @@ impl<'a> Parser<'a> {
1111
1114
first = false ;
1112
1115
} else {
1113
1116
if let Err ( mut e) = self . expect ( t) {
1117
+ if self . prevent_recovery {
1118
+ return Err ( e) ;
1119
+ }
1114
1120
// Attempt to keep parsing if it was a similar separator
1115
1121
if let Some ( ref tokens) = t. similar_tokens ( ) {
1116
1122
if tokens. contains ( & self . token ) {
@@ -1725,11 +1731,10 @@ impl<'a> Parser<'a> {
1725
1731
} else if self . eat_keyword ( keywords:: Const ) {
1726
1732
Mutability :: Immutable
1727
1733
} else {
1728
- let span = self . prev_span ;
1729
- self . span_err ( span,
1730
- "expected mut or const in raw pointer type (use \
1731
- `*mut T` or `*const T` as appropriate)") ;
1732
- Mutability :: Immutable
1734
+ let mut err = self . fatal ( "expected mut or const in raw pointer type (use \
1735
+ `*mut T` or `*const T` as appropriate)") ;
1736
+ err. span_label ( self . prev_span , "expected mut or const" ) ;
1737
+ return Err ( err) ;
1733
1738
} ;
1734
1739
let t = self . parse_ty_no_plus ( ) ?;
1735
1740
Ok ( MutTy { ty : t, mutbl : mutbl } )
@@ -2041,20 +2046,32 @@ impl<'a> Parser<'a> {
2041
2046
-> PResult < ' a , PathSegment > {
2042
2047
let ident = self . parse_path_segment_ident ( ) ?;
2043
2048
2044
- let is_args_start = |token : & token:: Token | match * token {
2045
- token:: Lt | token:: BinOp ( token:: Shl ) | token:: OpenDelim ( token:: Paren ) => true ,
2049
+ let is_args_start = |token : & token:: Token , include_paren : bool | match * token {
2050
+ token:: Lt | token:: BinOp ( token:: Shl ) => true ,
2051
+ token:: OpenDelim ( token:: Paren ) => include_paren,
2046
2052
_ => false ,
2047
2053
} ;
2048
- let check_args_start = |this : & mut Self | {
2049
- this. expected_tokens . extend_from_slice (
2050
- & [ TokenType :: Token ( token:: Lt ) , TokenType :: Token ( token:: OpenDelim ( token:: Paren ) ) ]
2051
- ) ;
2052
- is_args_start ( & this. token )
2054
+ let check_args_start = |this : & mut Self , include_paren : bool | {
2055
+ this. expected_tokens . push ( TokenType :: Token ( token:: Lt ) ) ;
2056
+ if include_paren {
2057
+ this. expected_tokens . push ( TokenType :: Token ( token:: OpenDelim ( token:: Paren ) ) ) ;
2058
+ }
2059
+ is_args_start ( & this. token , include_paren)
2053
2060
} ;
2054
2061
2055
- Ok ( if style == PathStyle :: Type && check_args_start ( self ) ||
2056
- style != PathStyle :: Mod && self . check ( & token:: ModSep )
2057
- && self . look_ahead ( 1 , |t| is_args_start ( t) ) {
2062
+ let mut parser_snapshot_before_generics = None ;
2063
+
2064
+ Ok ( if style == PathStyle :: Type && check_args_start ( self , true )
2065
+ || style != PathStyle :: Mod && self . check ( & token:: ModSep )
2066
+ && self . look_ahead ( 1 , |t| is_args_start ( t, true ) )
2067
+ || style == PathStyle :: Expr && check_args_start ( self , false ) && {
2068
+ // Check for generic arguments in an expression without a disambiguating `::`.
2069
+ // We have to save a snapshot, because it could end up being an expression
2070
+ // instead.
2071
+ parser_snapshot_before_generics = Some ( self . clone ( ) ) ;
2072
+ self . prevent_recovery = true ;
2073
+ true
2074
+ } {
2058
2075
// Generic arguments are found - `<`, `(`, `::<` or `::(`.
2059
2076
let lo = self . span ;
2060
2077
if self . eat ( & token:: ModSep ) && style == PathStyle :: Type && enable_warning {
@@ -2064,10 +2081,26 @@ impl<'a> Parser<'a> {
2064
2081
2065
2082
let args = if self . eat_lt ( ) {
2066
2083
// `<'a, T, A = U>`
2067
- let ( args, bindings) = self . parse_generic_args ( ) ?;
2068
- self . expect_gt ( ) ?;
2069
- let span = lo. to ( self . prev_span ) ;
2070
- AngleBracketedArgs { args, bindings, span } . into ( )
2084
+ let args: PResult < _ > = do catch {
2085
+ let ( args, bindings) = self . parse_generic_args ( ) ?;
2086
+ self . expect_gt ( ) ?;
2087
+ let span = lo. to ( self . prev_span ) ;
2088
+ AngleBracketedArgs { args, bindings, span }
2089
+ } ;
2090
+
2091
+ match args {
2092
+ Err ( mut err) => {
2093
+ if let Some ( snapshot) = parser_snapshot_before_generics {
2094
+ err. cancel ( ) ;
2095
+ mem:: replace ( self , snapshot) ;
2096
+ return Ok ( PathSegment :: from_ident ( ident) ) ;
2097
+ }
2098
+ return Err ( err) ;
2099
+ }
2100
+ _ => {
2101
+ args?. into ( )
2102
+ }
2103
+ }
2071
2104
} else {
2072
2105
// `(T, U) -> R`
2073
2106
self . bump ( ) ; // `(`
0 commit comments