@@ -1156,6 +1156,7 @@ impl<'a> Parser<'a> {
11561156 None => token:: CloseDelim ( self . token_cursor . frame . delim ) ,
11571157 } )
11581158 }
1159+
11591160 fn look_ahead_span ( & self , dist : usize ) -> Span {
11601161 if dist == 0 {
11611162 return self . span
@@ -4268,7 +4269,16 @@ impl<'a> Parser<'a> {
42684269 let mut stmts = vec ! [ ] ;
42694270
42704271 while !self . eat ( & token:: CloseDelim ( token:: Brace ) ) {
4271- if let Some ( stmt) = self . parse_full_stmt ( false ) ? {
4272+ let stmt = match self . parse_full_stmt ( false ) {
4273+ Err ( mut err) => {
4274+ err. emit ( ) ;
4275+ self . recover_stmt_ ( SemiColonMode :: Ignore , BlockMode :: Break ) ;
4276+ self . eat ( & token:: CloseDelim ( token:: Brace ) ) ;
4277+ break ;
4278+ }
4279+ Ok ( stmt) => stmt,
4280+ } ;
4281+ if let Some ( stmt) = stmt {
42724282 stmts. push ( stmt) ;
42734283 } else if self . token == token:: Eof {
42744284 break ;
@@ -4277,7 +4287,6 @@ impl<'a> Parser<'a> {
42774287 continue ;
42784288 } ;
42794289 }
4280-
42814290 Ok ( P ( ast:: Block {
42824291 stmts,
42834292 id : ast:: DUMMY_NODE_ID ,
@@ -5325,18 +5334,45 @@ impl<'a> Parser<'a> {
53255334 Ok ( ( class_name, ItemKind :: Union ( vdata, generics) , None ) )
53265335 }
53275336
5337+ fn consume_block ( & mut self , delim : token:: DelimToken ) {
5338+ let mut brace_depth = 0 ;
5339+ if !self . eat ( & token:: OpenDelim ( delim) ) {
5340+ return ;
5341+ }
5342+ loop {
5343+ if self . eat ( & token:: OpenDelim ( delim) ) {
5344+ brace_depth += 1 ;
5345+ } else if self . eat ( & token:: CloseDelim ( delim) ) {
5346+ if brace_depth == 0 {
5347+ return ;
5348+ } else {
5349+ brace_depth -= 1 ;
5350+ continue ;
5351+ }
5352+ } else if self . eat ( & token:: Eof ) || self . eat ( & token:: CloseDelim ( token:: NoDelim ) ) {
5353+ return ;
5354+ } else {
5355+ self . bump ( ) ;
5356+ }
5357+ }
5358+ }
5359+
53285360 pub fn parse_record_struct_body ( & mut self ) -> PResult < ' a , Vec < StructField > > {
53295361 let mut fields = Vec :: new ( ) ;
53305362 if self . eat ( & token:: OpenDelim ( token:: Brace ) ) {
53315363 while self . token != token:: CloseDelim ( token:: Brace ) {
5332- fields . push ( self . parse_struct_decl_field ( ) . map_err ( |e| {
5364+ let field = self . parse_struct_decl_field ( ) . map_err ( |e| {
53335365 self . recover_stmt ( ) ;
5334- self . eat ( & token:: CloseDelim ( token:: Brace ) ) ;
53355366 e
5336- } ) ?) ;
5367+ } ) ;
5368+ match field {
5369+ Ok ( field) => fields. push ( field) ,
5370+ Err ( mut err) => {
5371+ err. emit ( ) ;
5372+ }
5373+ }
53375374 }
5338-
5339- self . bump ( ) ;
5375+ self . eat ( & token:: CloseDelim ( token:: Brace ) ) ;
53405376 } else {
53415377 let token_str = self . this_token_to_string ( ) ;
53425378 return Err ( self . fatal ( & format ! ( "expected `where`, or `{{` after struct \
@@ -5384,8 +5420,15 @@ impl<'a> Parser<'a> {
53845420 self . bump ( ) ;
53855421 }
53865422 token:: CloseDelim ( token:: Brace ) => { }
5387- token:: DocComment ( _) => return Err ( self . span_fatal_err ( self . span ,
5388- Error :: UselessDocComment ) ) ,
5423+ token:: DocComment ( _) => {
5424+ let mut err = self . span_fatal_err ( self . span , Error :: UselessDocComment ) ;
5425+ self . bump ( ) ; // consume the doc comment
5426+ if self . eat ( & token:: Comma ) || self . token == token:: CloseDelim ( token:: Brace ) {
5427+ err. emit ( ) ;
5428+ } else {
5429+ return Err ( err) ;
5430+ }
5431+ }
53895432 _ => return Err ( self . span_fatal_help ( self . span ,
53905433 & format ! ( "expected `,`, or `}}`, found `{}`" , self . this_token_to_string( ) ) ,
53915434 "struct fields should be separated by commas" ) ) ,
@@ -6241,7 +6284,65 @@ impl<'a> Parser<'a> {
62416284 return Ok ( Some ( macro_def) ) ;
62426285 }
62436286
6244- self . parse_macro_use_or_failure ( attrs, macros_allowed, attributes_allowed, lo, visibility)
6287+ // Verify wether we have encountered a struct or method definition where the user forgot to
6288+ // add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
6289+ if visibility == Visibility :: Public &&
6290+ self . check_ident ( ) &&
6291+ self . look_ahead ( 1 , |t| * t != token:: Not )
6292+ {
6293+ // Space between `pub` keyword and the identifier
6294+ //
6295+ // pub S {}
6296+ // ^^^ `sp` points here
6297+ let sp = self . prev_span . between ( self . span ) ;
6298+ let full_sp = self . prev_span . to ( self . span ) ;
6299+ let ident_sp = self . span ;
6300+ if self . look_ahead ( 1 , |t| * t == token:: OpenDelim ( token:: Brace ) ) {
6301+ // possible public struct definition where `struct` was forgotten
6302+ let ident = self . parse_ident ( ) . unwrap ( ) ;
6303+ let msg = format ! ( "add `struct` here to parse `{}` as a public struct" ,
6304+ ident) ;
6305+ let mut err = self . diagnostic ( )
6306+ . struct_span_err ( sp, "missing `struct` for struct definition" ) ;
6307+ err. span_suggestion_short ( sp, & msg, " struct " . into ( ) ) ;
6308+ return Err ( err) ;
6309+ } else if self . look_ahead ( 1 , |t| * t == token:: OpenDelim ( token:: Paren ) ) {
6310+ let ident = self . parse_ident ( ) . unwrap ( ) ;
6311+ self . consume_block ( token:: Paren ) ;
6312+ let ( kw, kw_name, ambiguous) = if self . check ( & token:: RArrow ) ||
6313+ self . check ( & token:: OpenDelim ( token:: Brace ) )
6314+ {
6315+ ( "fn" , "method" , false )
6316+ } else if self . check ( & token:: Colon ) {
6317+ let kw = "struct" ;
6318+ ( kw, kw, false )
6319+ } else {
6320+ ( "fn` or `struct" , "method or struct" , true )
6321+ } ;
6322+
6323+ let msg = format ! ( "missing `{}` for {} definition" , kw, kw_name) ;
6324+ let mut err = self . diagnostic ( ) . struct_span_err ( sp, & msg) ;
6325+ if !ambiguous {
6326+ let suggestion = format ! ( "add `{}` here to parse `{}` as a public {}" ,
6327+ kw,
6328+ ident,
6329+ kw_name) ;
6330+ err. span_suggestion_short ( sp, & suggestion, format ! ( " {} " , kw) ) ;
6331+ } else {
6332+ if let Ok ( snippet) = self . sess . codemap ( ) . span_to_snippet ( ident_sp) {
6333+ err. span_suggestion (
6334+ full_sp,
6335+ "if you meant to call a macro, write instead" ,
6336+ format ! ( "{}!" , snippet) ) ;
6337+ } else {
6338+ err. help ( "if you meant to call a macro, remove the `pub` \
6339+ and add a trailing `!` after the identifier") ;
6340+ }
6341+ }
6342+ return Err ( err) ;
6343+ }
6344+ }
6345+ self . parse_macro_use_or_failure ( attrs, macros_allowed, attributes_allowed, lo, visibility)
62456346 }
62466347
62476348 /// Parse a foreign item.
0 commit comments