@@ -1156,6 +1156,7 @@ impl<'a> Parser<'a> {
1156
1156
None => token:: CloseDelim ( self . token_cursor . frame . delim ) ,
1157
1157
} )
1158
1158
}
1159
+
1159
1160
fn look_ahead_span ( & self , dist : usize ) -> Span {
1160
1161
if dist == 0 {
1161
1162
return self . span
@@ -4268,7 +4269,16 @@ impl<'a> Parser<'a> {
4268
4269
let mut stmts = vec ! [ ] ;
4269
4270
4270
4271
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 {
4272
4282
stmts. push ( stmt) ;
4273
4283
} else if self . token == token:: Eof {
4274
4284
break ;
@@ -4277,7 +4287,6 @@ impl<'a> Parser<'a> {
4277
4287
continue ;
4278
4288
} ;
4279
4289
}
4280
-
4281
4290
Ok ( P ( ast:: Block {
4282
4291
stmts,
4283
4292
id : ast:: DUMMY_NODE_ID ,
@@ -5325,18 +5334,45 @@ impl<'a> Parser<'a> {
5325
5334
Ok ( ( class_name, ItemKind :: Union ( vdata, generics) , None ) )
5326
5335
}
5327
5336
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
+
5328
5360
pub fn parse_record_struct_body ( & mut self ) -> PResult < ' a , Vec < StructField > > {
5329
5361
let mut fields = Vec :: new ( ) ;
5330
5362
if self . eat ( & token:: OpenDelim ( token:: Brace ) ) {
5331
5363
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| {
5333
5365
self . recover_stmt ( ) ;
5334
- self . eat ( & token:: CloseDelim ( token:: Brace ) ) ;
5335
5366
e
5336
- } ) ?) ;
5367
+ } ) ;
5368
+ match field {
5369
+ Ok ( field) => fields. push ( field) ,
5370
+ Err ( mut err) => {
5371
+ err. emit ( ) ;
5372
+ }
5373
+ }
5337
5374
}
5338
-
5339
- self . bump ( ) ;
5375
+ self . eat ( & token:: CloseDelim ( token:: Brace ) ) ;
5340
5376
} else {
5341
5377
let token_str = self . this_token_to_string ( ) ;
5342
5378
return Err ( self . fatal ( & format ! ( "expected `where`, or `{{` after struct \
@@ -5384,8 +5420,15 @@ impl<'a> Parser<'a> {
5384
5420
self . bump ( ) ;
5385
5421
}
5386
5422
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
+ }
5389
5432
_ => return Err ( self . span_fatal_help ( self . span ,
5390
5433
& format ! ( "expected `,`, or `}}`, found `{}`" , self . this_token_to_string( ) ) ,
5391
5434
"struct fields should be separated by commas" ) ) ,
@@ -6241,7 +6284,65 @@ impl<'a> Parser<'a> {
6241
6284
return Ok ( Some ( macro_def) ) ;
6242
6285
}
6243
6286
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)
6245
6346
}
6246
6347
6247
6348
/// Parse a foreign item.
0 commit comments