@@ -239,6 +239,7 @@ impl<'a> Parser<'a> {
239239 self . recover_const_impl ( const_span, attrs, def_ ( ) ) ?
240240 } else {
241241 self . recover_const_mut ( const_span) ;
242+ self . recover_missing_kw_before_item ( ) ?;
242243 let ( ident, generics, ty, expr) = self . parse_const_item ( ) ?;
243244 (
244245 ident,
@@ -311,6 +312,9 @@ impl<'a> Parser<'a> {
311312 Case :: Insensitive ,
312313 ) ;
313314 } else if macros_allowed && self . check_path ( ) {
315+ if self . isnt_macro_invocation ( ) {
316+ self . recover_missing_kw_before_item ( ) ?;
317+ }
314318 // MACRO INVOCATION ITEM
315319 ( Ident :: empty ( ) , ItemKind :: MacCall ( P ( self . parse_item_macro ( vis) ?) ) )
316320 } else {
@@ -374,25 +378,25 @@ impl<'a> Parser<'a> {
374378 self . check_ident ( ) && self . look_ahead ( 1 , |t| * t != token:: Not && * t != token:: PathSep )
375379 }
376380
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
379383 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 ) ;
386- let ident_sp = self . token . span ;
387-
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- } ) {
384+ let is_pub = self . prev_token . is_keyword ( kw :: Pub ) ;
385+ let is_const = self . prev_token . is_keyword ( kw :: Const ) ;
386+ let ident_span = self . token . span ;
387+ let span = if is_pub { self . prev_token . span . to ( ident_span ) } else { ident_span } ;
388+ let insert_span = ident_span . shrink_to_lo ( ) ;
389+
390+ let ident = if ( !is_const
391+ || self . look_ahead ( 1 , |t| * t == token :: OpenDelim ( Delimiter :: Parenthesis ) ) )
392+ && self . look_ahead ( 1 , |t| {
393+ [
394+ token:: Lt ,
395+ token:: OpenDelim ( Delimiter :: Brace ) ,
396+ token:: OpenDelim ( Delimiter :: Parenthesis ) ,
397+ ]
398+ . contains ( & t. kind )
399+ } ) {
396400 self . parse_ident ( ) . unwrap ( )
397401 } else {
398402 return Ok ( ( ) ) ;
@@ -406,46 +410,56 @@ impl<'a> Parser<'a> {
406410 }
407411
408412 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 } )
413+ // possible struct or enum definition where `struct` or `enum` was forgotten
414+ if self . look_ahead ( 1 , |t| * t == token:: CloseDelim ( Delimiter :: Brace ) ) {
415+ // `S {}` could be unit enum or struct
416+ Some ( errors:: MissingKeywordForItemDefinition :: EnumOrStruct { span } )
417+ } else if self . look_ahead ( 2 , |t| * t == token:: Colon )
418+ || self . look_ahead ( 3 , |t| * t == token:: Colon )
419+ {
420+ // `S { f:` or `S { pub f:`
421+ Some ( errors:: MissingKeywordForItemDefinition :: Struct { span, insert_span, ident } )
422+ } else {
423+ Some ( errors:: MissingKeywordForItemDefinition :: Enum { span, insert_span, ident } )
424+ }
411425 } else if self . check ( & token:: OpenDelim ( Delimiter :: Parenthesis ) ) {
412- // possible public function or tuple struct definition where `fn`/`struct` was
413- // forgotten
426+ // possible function or tuple struct definition where `fn` or `struct` was forgotten
414427 self . bump ( ) ; // `(`
415428 let is_method = self . recover_self_param ( ) ;
416429
417430 self . consume_block ( Delimiter :: Parenthesis , ConsumeClosingDelim :: Yes ) ;
418431
419- let err =
420- if self . check ( & token:: RArrow ) || self . check ( & token:: OpenDelim ( Delimiter :: Brace ) ) {
421- self . eat_to_tokens ( & [ & token:: OpenDelim ( Delimiter :: Brace ) ] ) ;
422- self . bump ( ) ; // `{`
423- self . consume_block ( Delimiter :: Brace , ConsumeClosingDelim :: Yes ) ;
424- if is_method {
425- errors:: MissingKeywordForItemDefinition :: Method { span : sp, ident }
426- } else {
427- errors:: MissingKeywordForItemDefinition :: Function { span : sp, ident }
428- }
429- } else if self . check ( & token:: Semi ) {
430- errors:: MissingKeywordForItemDefinition :: Struct { span : sp, ident }
432+ let err = if self . check ( & token:: RArrow )
433+ || self . check ( & token:: OpenDelim ( Delimiter :: Brace ) )
434+ {
435+ self . eat_to_tokens ( & [ & token:: OpenDelim ( Delimiter :: Brace ) ] ) ;
436+ self . bump ( ) ; // `{`
437+ self . consume_block ( Delimiter :: Brace , ConsumeClosingDelim :: Yes ) ;
438+ if is_method {
439+ errors:: MissingKeywordForItemDefinition :: Method { span, insert_span, ident }
431440 } else {
432- errors:: MissingKeywordForItemDefinition :: Ambiguous {
433- span : sp,
434- subdiag : if found_generics {
435- None
436- } else if let Ok ( snippet) = self . span_to_snippet ( ident_sp) {
437- Some ( errors:: AmbiguousMissingKwForItemSub :: SuggestMacro {
438- span : full_sp,
439- snippet,
440- } )
441- } else {
442- Some ( errors:: AmbiguousMissingKwForItemSub :: HelpMacro )
443- } ,
444- }
445- } ;
441+ errors:: MissingKeywordForItemDefinition :: Function { span, insert_span, ident }
442+ }
443+ } else if is_pub && self . check ( & token:: Semi ) {
444+ errors:: MissingKeywordForItemDefinition :: Struct { span, insert_span, ident }
445+ } else {
446+ errors:: MissingKeywordForItemDefinition :: Ambiguous {
447+ span,
448+ subdiag : if found_generics {
449+ None
450+ } else if let Ok ( snippet) = self . span_to_snippet ( ident_span) {
451+ Some ( errors:: AmbiguousMissingKwForItemSub :: SuggestMacro {
452+ span : ident_span,
453+ snippet,
454+ } )
455+ } else {
456+ Some ( errors:: AmbiguousMissingKwForItemSub :: HelpMacro )
457+ } ,
458+ }
459+ } ;
446460 Some ( err)
447461 } else if found_generics {
448- Some ( errors:: MissingKeywordForItemDefinition :: Ambiguous { span : sp , subdiag : None } )
462+ Some ( errors:: MissingKeywordForItemDefinition :: Ambiguous { span, subdiag : None } )
449463 } else {
450464 None
451465 } ;
0 commit comments