@@ -17,6 +17,7 @@ use rustc_span::edit_distance::edit_distance;
17
17
use rustc_span:: edition:: Edition ;
18
18
use rustc_span:: source_map;
19
19
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
20
+ use rustc_span:: ErrorGuaranteed ;
20
21
use rustc_span:: { Span , DUMMY_SP } ;
21
22
use std:: fmt:: Write ;
22
23
use std:: mem;
@@ -2332,14 +2333,106 @@ impl<'a> Parser<'a> {
2332
2333
}
2333
2334
}
2334
2335
} ;
2336
+
2337
+ // Store the end of function parameters to give better diagnostics
2338
+ // inside `parse_fn_body()`.
2339
+ let fn_params_end = self . prev_token . span . shrink_to_hi ( ) ;
2340
+
2335
2341
generics. where_clause = self . parse_where_clause ( ) ?; // `where T: Ord`
2336
2342
2343
+ // `fn_params_end` is needed only when it's followed by a where clause.
2344
+ let fn_params_end =
2345
+ if generics. where_clause . has_where_token { Some ( fn_params_end) } else { None } ;
2346
+
2337
2347
let mut sig_hi = self . prev_token . span ;
2338
- let body = self . parse_fn_body ( attrs, & ident, & mut sig_hi, fn_parse_mode. req_body ) ?; // `;` or `{ ... }`.
2348
+ // Either `;` or `{ ... }`.
2349
+ let body =
2350
+ self . parse_fn_body ( attrs, & ident, & mut sig_hi, fn_parse_mode. req_body , fn_params_end) ?;
2339
2351
let fn_sig_span = sig_lo. to ( sig_hi) ;
2340
2352
Ok ( ( ident, FnSig { header, decl, span : fn_sig_span } , generics, body) )
2341
2353
}
2342
2354
2355
+ /// Provide diagnostics when function body is not found
2356
+ fn error_fn_body_not_found (
2357
+ & mut self ,
2358
+ ident_span : Span ,
2359
+ req_body : bool ,
2360
+ fn_params_end : Option < Span > ,
2361
+ ) -> PResult < ' a , ErrorGuaranteed > {
2362
+ let expected = if req_body {
2363
+ & [ token:: OpenDelim ( Delimiter :: Brace ) ] [ ..]
2364
+ } else {
2365
+ & [ token:: Semi , token:: OpenDelim ( Delimiter :: Brace ) ]
2366
+ } ;
2367
+ match self . expected_one_of_not_found ( & [ ] , expected) {
2368
+ Ok ( error_guaranteed) => Ok ( error_guaranteed) ,
2369
+ Err ( mut err) => {
2370
+ if self . token . kind == token:: CloseDelim ( Delimiter :: Brace ) {
2371
+ // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
2372
+ // the AST for typechecking.
2373
+ err. span_label ( ident_span, "while parsing this `fn`" ) ;
2374
+ Ok ( err. emit ( ) )
2375
+ } else if self . token . kind == token:: RArrow
2376
+ && let Some ( fn_params_end) = fn_params_end
2377
+ {
2378
+ // Instead of a function body, the parser has encountered a right arrow
2379
+ // preceded by a where clause.
2380
+
2381
+ // Find whether token behind the right arrow is a function trait and
2382
+ // store its span.
2383
+ let fn_trait_span =
2384
+ [ sym:: FnOnce , sym:: FnMut , sym:: Fn ] . into_iter ( ) . find_map ( |symbol| {
2385
+ if self . prev_token . is_ident_named ( symbol) {
2386
+ Some ( self . prev_token . span )
2387
+ } else {
2388
+ None
2389
+ }
2390
+ } ) ;
2391
+
2392
+ // Parse the return type (along with the right arrow) and store its span.
2393
+ // If there's a parse error, cancel it and return the existing error
2394
+ // as we are primarily concerned with the
2395
+ // expected-function-body-but-found-something-else error here.
2396
+ let arrow_span = self . token . span ;
2397
+ let ty_span = match self . parse_ret_ty (
2398
+ AllowPlus :: Yes ,
2399
+ RecoverQPath :: Yes ,
2400
+ RecoverReturnSign :: Yes ,
2401
+ ) {
2402
+ Ok ( ty_span) => ty_span. span ( ) . shrink_to_hi ( ) ,
2403
+ Err ( parse_error) => {
2404
+ parse_error. cancel ( ) ;
2405
+ return Err ( err) ;
2406
+ }
2407
+ } ;
2408
+ let ret_ty_span = arrow_span. to ( ty_span) ;
2409
+
2410
+ if let Some ( fn_trait_span) = fn_trait_span {
2411
+ // Typo'd Fn* trait bounds such as
2412
+ // fn foo<F>() where F: FnOnce -> () {}
2413
+ err. subdiagnostic ( errors:: FnTraitMissingParen { span : fn_trait_span } ) ;
2414
+ } else if let Ok ( snippet) = self . psess . source_map ( ) . span_to_snippet ( ret_ty_span)
2415
+ {
2416
+ // If token behind right arrow is not a Fn* trait, the programmer
2417
+ // probably misplaced the return type after the where clause like
2418
+ // `fn foo<T>() where T: Default -> u8 {}`
2419
+ err. primary_message (
2420
+ "return type should be specified after the function parameters" ,
2421
+ ) ;
2422
+ err. subdiagnostic ( errors:: MisplacedReturnType {
2423
+ fn_params_end,
2424
+ snippet,
2425
+ ret_ty_span,
2426
+ } ) ;
2427
+ }
2428
+ Err ( err)
2429
+ } else {
2430
+ Err ( err)
2431
+ }
2432
+ }
2433
+ }
2434
+ }
2435
+
2343
2436
/// Parse the "body" of a function.
2344
2437
/// This can either be `;` when there's no body,
2345
2438
/// or e.g. a block when the function is a provided one.
@@ -2349,6 +2442,7 @@ impl<'a> Parser<'a> {
2349
2442
ident : & Ident ,
2350
2443
sig_hi : & mut Span ,
2351
2444
req_body : bool ,
2445
+ fn_params_end : Option < Span > ,
2352
2446
) -> PResult < ' a , Option < P < Block > > > {
2353
2447
let has_semi = if req_body {
2354
2448
self . token . kind == TokenKind :: Semi
@@ -2377,33 +2471,7 @@ impl<'a> Parser<'a> {
2377
2471
} ) ;
2378
2472
( AttrVec :: new ( ) , Some ( self . mk_block_err ( span, guar) ) )
2379
2473
} else {
2380
- let expected = if req_body {
2381
- & [ token:: OpenDelim ( Delimiter :: Brace ) ] [ ..]
2382
- } else {
2383
- & [ token:: Semi , token:: OpenDelim ( Delimiter :: Brace ) ]
2384
- } ;
2385
- if let Err ( mut err) = self . expected_one_of_not_found ( & [ ] , expected) {
2386
- if self . token . kind == token:: CloseDelim ( Delimiter :: Brace ) {
2387
- // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
2388
- // the AST for typechecking.
2389
- err. span_label ( ident. span , "while parsing this `fn`" ) ;
2390
- err. emit ( ) ;
2391
- } else {
2392
- // check for typo'd Fn* trait bounds such as
2393
- // fn foo<F>() where F: FnOnce -> () {}
2394
- if self . token . kind == token:: RArrow {
2395
- let machine_applicable = [ sym:: FnOnce , sym:: FnMut , sym:: Fn ]
2396
- . into_iter ( )
2397
- . any ( |s| self . prev_token . is_ident_named ( s) ) ;
2398
-
2399
- err. subdiagnostic ( errors:: FnTraitMissingParen {
2400
- span : self . prev_token . span ,
2401
- machine_applicable,
2402
- } ) ;
2403
- }
2404
- return Err ( err) ;
2405
- }
2406
- }
2474
+ self . error_fn_body_not_found ( ident. span , req_body, fn_params_end) ?;
2407
2475
( AttrVec :: new ( ) , None )
2408
2476
} ;
2409
2477
attrs. extend ( inner_attrs) ;
0 commit comments