@@ -239,6 +239,7 @@ impl<'a> Parser<'a> {
239
239
self . recover_const_impl ( const_span, attrs, def_ ( ) ) ?
240
240
} else {
241
241
self . recover_const_mut ( const_span) ;
242
+ self . recover_missing_kw_before_item ( ) ?;
242
243
let ( ident, generics, ty, expr) = self . parse_const_item ( ) ?;
243
244
(
244
245
ident,
@@ -311,6 +312,9 @@ impl<'a> Parser<'a> {
311
312
Case :: Insensitive ,
312
313
) ;
313
314
} else if macros_allowed && self . check_path ( ) {
315
+ if self . isnt_macro_invocation ( ) {
316
+ self . recover_missing_kw_before_item ( ) ?;
317
+ }
314
318
// MACRO INVOCATION ITEM
315
319
( Ident :: empty ( ) , ItemKind :: MacCall ( P ( self . parse_item_macro ( vis) ?) ) )
316
320
} else {
@@ -374,25 +378,24 @@ impl<'a> Parser<'a> {
374
378
self . check_ident ( ) && self . look_ahead ( 1 , |t| * t != token:: Not && * t != token:: PathSep )
375
379
}
376
380
377
- /// Recover on encountering a struct or method definition where the user
378
- /// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`.
381
+ /// Recover on encountering a struct, enum, or method definition where the user
382
+ /// forgot to add the `struct`, `enum`, or `fn` keyword
379
383
fn recover_missing_kw_before_item ( & mut self ) -> PResult < ' a , ( ) > {
380
- // Space between `pub` keyword and the identifier
381
- //
382
- // pub S {}
383
- // ^^^ `sp` points here
384
- let sp = self . prev_token . span . between ( self . token . span ) ;
385
- let full_sp = self . prev_token . span . to ( self . token . span ) ;
384
+ let is_pub = self . prev_token . is_keyword ( kw:: Pub ) ;
385
+ let is_const = self . prev_token . is_keyword ( kw:: Const ) ;
386
+ let sp = self . token . span . shrink_to_lo ( ) ;
386
387
let ident_sp = self . token . span ;
387
388
388
- let ident = if self . look_ahead ( 1 , |t| {
389
- [
390
- token:: Lt ,
391
- token:: OpenDelim ( Delimiter :: Brace ) ,
392
- token:: OpenDelim ( Delimiter :: Parenthesis ) ,
393
- ]
394
- . contains ( & t. kind )
395
- } ) {
389
+ let ident = if ( !is_const
390
+ || self . look_ahead ( 1 , |t| * t == token:: OpenDelim ( Delimiter :: Parenthesis ) ) )
391
+ && self . look_ahead ( 1 , |t| {
392
+ [
393
+ token:: Lt ,
394
+ token:: OpenDelim ( Delimiter :: Brace ) ,
395
+ token:: OpenDelim ( Delimiter :: Parenthesis ) ,
396
+ ]
397
+ . contains ( & t. kind )
398
+ } ) {
396
399
self . parse_ident ( ) . unwrap ( )
397
400
} else {
398
401
return Ok ( ( ) ) ;
@@ -406,11 +409,17 @@ impl<'a> Parser<'a> {
406
409
}
407
410
408
411
let err = if self . check ( & token:: OpenDelim ( Delimiter :: Brace ) ) {
409
- // possible public struct definition where `struct` was forgotten
410
- Some ( errors:: MissingKeywordForItemDefinition :: Struct { span : sp, ident } )
412
+ // possible struct or enum definition where `struct` or `enum` was forgotten
413
+ if self . look_ahead ( 1 , |t| * t == token:: CloseDelim ( Delimiter :: Brace ) )
414
+ || self . look_ahead ( 2 , |t| * t == token:: Colon )
415
+ || self . look_ahead ( 3 , |t| * t == token:: Colon )
416
+ {
417
+ Some ( errors:: MissingKeywordForItemDefinition :: Struct { span : sp, ident } )
418
+ } else {
419
+ Some ( errors:: MissingKeywordForItemDefinition :: Enum { span : sp, ident } )
420
+ }
411
421
} else if self . check ( & token:: OpenDelim ( Delimiter :: Parenthesis ) ) {
412
- // possible public function or tuple struct definition where `fn`/`struct` was
413
- // forgotten
422
+ // possible function or tuple struct definition where `fn` or `struct` was forgotten
414
423
self . bump ( ) ; // `(`
415
424
let is_method = self . recover_self_param ( ) ;
416
425
@@ -426,7 +435,7 @@ impl<'a> Parser<'a> {
426
435
} else {
427
436
errors:: MissingKeywordForItemDefinition :: Function { span : sp, ident }
428
437
}
429
- } else if self . check ( & token:: Semi ) {
438
+ } else if is_pub && self . check ( & token:: Semi ) {
430
439
errors:: MissingKeywordForItemDefinition :: Struct { span : sp, ident }
431
440
} else {
432
441
errors:: MissingKeywordForItemDefinition :: Ambiguous {
@@ -435,7 +444,7 @@ impl<'a> Parser<'a> {
435
444
None
436
445
} else if let Ok ( snippet) = self . span_to_snippet ( ident_sp) {
437
446
Some ( errors:: AmbiguousMissingKwForItemSub :: SuggestMacro {
438
- span : full_sp ,
447
+ span : ident_sp ,
439
448
snippet,
440
449
} )
441
450
} else {
0 commit comments