@@ -2332,10 +2332,20 @@ impl<'a> Parser<'a> {
23322332 }
23332333 }
23342334 } ;
2335+
2336+ // Store the end of function parameters to give better diagnostics
2337+ // inside `parse_fn_body()`.
2338+ let fn_params_end = self . prev_token . span . shrink_to_hi ( ) ;
2339+
23352340 generics. where_clause = self . parse_where_clause ( ) ?; // `where T: Ord`
23362341
2342+ // `fn_params_end` is needed only when it's followed by a where clause.
2343+ let fn_params_end =
2344+ if generics. where_clause . has_where_token { Some ( fn_params_end) } else { None } ;
2345+
23372346 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 `{ ... }`.
2347+ let body =
2348+ self . parse_fn_body ( attrs, & ident, & mut sig_hi, fn_parse_mode. req_body , fn_params_end) ?; // `;` or `{ ... }`.
23392349 let fn_sig_span = sig_lo. to ( sig_hi) ;
23402350 Ok ( ( ident, FnSig { header, decl, span : fn_sig_span } , generics, body) )
23412351 }
@@ -2349,6 +2359,7 @@ impl<'a> Parser<'a> {
23492359 ident : & Ident ,
23502360 sig_hi : & mut Span ,
23512361 req_body : bool ,
2362+ fn_params_end : Option < Span > ,
23522363 ) -> PResult < ' a , Option < P < Block > > > {
23532364 let has_semi = if req_body {
23542365 self . token . kind == TokenKind :: Semi
@@ -2388,20 +2399,58 @@ impl<'a> Parser<'a> {
23882399 // the AST for typechecking.
23892400 err. span_label ( ident. span , "while parsing this `fn`" ) ;
23902401 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+ } else if self . token . kind == token:: RArrow
2403+ && let Some ( fn_params_end) = fn_params_end
2404+ {
2405+ // Instead of a function body, the parser has encountered a right arrow
2406+ // preceded by a where clause.
2407+
2408+ // Find whether token behind the right arrow is a function trait and
2409+ // store its span.
2410+ let prev_token_is_fn_trait = [ sym:: FnOnce , sym:: FnMut , sym:: Fn ]
2411+ . into_iter ( )
2412+ . any ( |s| self . prev_token . is_ident_named ( s) ) ;
2413+ let fn_trait_span = self . prev_token . span ;
2414+
2415+ // Parse the return type (along with the right arrow) and store its span.
2416+ // If there's a parse error, cancel it and return the existing error
2417+ // as we are primarily concerned with the
2418+ // expected-function-body-but-found-something-else error here.
2419+ let arrow_span = self . token . span ;
2420+ let ty_span = match self . parse_ret_ty (
2421+ AllowPlus :: Yes ,
2422+ RecoverQPath :: Yes ,
2423+ RecoverReturnSign :: Yes ,
2424+ ) {
2425+ Ok ( ty_span) => ty_span. span ( ) . shrink_to_hi ( ) ,
2426+ Err ( parse_error) => {
2427+ parse_error. cancel ( ) ;
2428+ return Err ( err) ;
2429+ }
2430+ } ;
2431+ let ret_ty_span = arrow_span. to ( ty_span) ;
2432+
2433+ if prev_token_is_fn_trait {
2434+ // Typo'd Fn* trait bounds such as
2435+ // fn foo<F>() where F: FnOnce -> () {}
2436+ err. subdiagnostic ( errors:: FnTraitMissingParen { span : fn_trait_span } ) ;
2437+ } else if let Ok ( snippet) = self . psess . source_map ( ) . span_to_snippet ( ret_ty_span)
2438+ {
2439+ // If token behind right arrow is not a Fn* trait, the programmer
2440+ // probably misplaced the return type after the where clause like
2441+ // `fn foo<T>() where T: Default -> u8 {}`
2442+ err. primary_message (
2443+ "return type should be specified after the function parameters" ,
2444+ ) ;
2445+ err. subdiagnostic ( errors:: MisplacedReturnType {
2446+ fn_params_end,
2447+ snippet,
2448+ ret_ty_span,
24022449 } ) ;
24032450 }
24042451 return Err ( err) ;
2452+ } else {
2453+ return Err ( err) ;
24052454 }
24062455 }
24072456 ( AttrVec :: new ( ) , None )
0 commit comments