@@ -13,7 +13,9 @@ use rustc_ast::walk_list;
1313use rustc_ast:: * ;
1414use rustc_ast_pretty:: pprust:: { self , State } ;
1515use rustc_data_structures:: fx:: FxHashMap ;
16- use rustc_errors:: { error_code, pluralize, struct_span_err, Applicability } ;
16+ use rustc_errors:: {
17+ error_code, pluralize, struct_span_err, Applicability , DiagnosticBuilder , ErrorGuaranteed ,
18+ } ;
1719use rustc_parse:: validate_attr;
1820use rustc_session:: lint:: builtin:: {
1921 DEPRECATED_WHERE_CLAUSE_LOCATION , MISSING_ABI , PATTERNS_IN_FNS_WITHOUT_BODY ,
@@ -476,22 +478,33 @@ impl<'a> AstValidator<'a> {
476478 }
477479
478480 fn error_item_without_body ( & self , sp : Span , ctx : & str , msg : & str , sugg : & str ) {
481+ self . error_item_without_body_with_help ( sp, ctx, msg, sugg, |_| ( ) ) ;
482+ }
483+
484+ fn error_item_without_body_with_help (
485+ & self ,
486+ sp : Span ,
487+ ctx : & str ,
488+ msg : & str ,
489+ sugg : & str ,
490+ help : impl FnOnce ( & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ) ,
491+ ) {
479492 let source_map = self . session . source_map ( ) ;
480493 let end = source_map. end_point ( sp) ;
481494 let replace_span = if source_map. span_to_snippet ( end) . map ( |s| s == ";" ) . unwrap_or ( false ) {
482495 end
483496 } else {
484497 sp. shrink_to_hi ( )
485498 } ;
486- self . err_handler ( )
487- . struct_span_err ( sp , msg )
488- . span_suggestion (
489- replace_span ,
490- & format ! ( "provide a definition for the {}" , ctx ) ,
491- sugg ,
492- Applicability :: HasPlaceholders ,
493- )
494- . emit ( ) ;
499+ let mut err = self . err_handler ( ) . struct_span_err ( sp , msg ) ;
500+ err . span_suggestion (
501+ replace_span ,
502+ & format ! ( "provide a definition for the {}" , ctx ) ,
503+ sugg ,
504+ Applicability :: HasPlaceholders ,
505+ ) ;
506+ help ( & mut err ) ;
507+ err . emit ( ) ;
495508 }
496509
497510 fn check_impl_item_provided < T > ( & self , sp : Span , body : & Option < T > , ctx : & str , sugg : & str ) {
@@ -630,7 +643,8 @@ impl<'a> AstValidator<'a> {
630643 match ( fk. ctxt ( ) , fk. header ( ) ) {
631644 ( Some ( FnCtxt :: Foreign ) , _) => return ,
632645 ( Some ( FnCtxt :: Free ) , Some ( header) ) => match header. ext {
633- Extern :: Explicit ( StrLit { symbol_unescaped : sym:: C , .. } ) | Extern :: Implicit
646+ Extern :: Explicit ( StrLit { symbol_unescaped : sym:: C , .. } , _)
647+ | Extern :: Implicit ( _)
634648 if matches ! ( header. unsafety, Unsafe :: Yes ( _) ) =>
635649 {
636650 return ;
@@ -842,7 +856,7 @@ impl<'a> AstValidator<'a> {
842856 . emit ( ) ;
843857 } ) ;
844858 self . check_late_bound_lifetime_defs ( & bfty. generic_params ) ;
845- if let Extern :: Implicit = bfty. ext {
859+ if let Extern :: Implicit ( _ ) = bfty. ext {
846860 let sig_span = self . session . source_map ( ) . next_point ( ty. span . shrink_to_lo ( ) ) ;
847861 self . maybe_lint_missing_abi ( sig_span, ty. id ) ;
848862 }
@@ -1190,8 +1204,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11901204
11911205 if body. is_none ( ) {
11921206 let msg = "free function without a body" ;
1193- self . error_item_without_body ( item. span , "function" , msg, " { <body> }" ) ;
1207+ let ext = sig. header . ext ;
1208+
1209+ let f = |e : & mut DiagnosticBuilder < ' _ , _ > | {
1210+ if let Extern :: Implicit ( start_span) | Extern :: Explicit ( _, start_span) = & ext
1211+ {
1212+ let start_suggestion = if let Extern :: Explicit ( abi, _) = ext {
1213+ format ! ( "extern \" {}\" {{" , abi. symbol_unescaped)
1214+ } else {
1215+ "extern {" . to_owned ( )
1216+ } ;
1217+
1218+ let end_suggestion = " }" . to_owned ( ) ;
1219+ let end_span = item. span . shrink_to_hi ( ) ;
1220+
1221+ e
1222+ . multipart_suggestion (
1223+ "if you meant to declare an externally defined function, use an `extern` block" ,
1224+ vec ! [ ( * start_span, start_suggestion) , ( end_span, end_suggestion) ] ,
1225+ Applicability :: MaybeIncorrect ,
1226+ ) ;
1227+ }
1228+ } ;
1229+
1230+ self . error_item_without_body_with_help (
1231+ item. span ,
1232+ "function" ,
1233+ msg,
1234+ " { <body> }" ,
1235+ f,
1236+ ) ;
11941237 }
1238+
11951239 self . visit_vis ( & item. vis ) ;
11961240 self . visit_ident ( item. ident ) ;
11971241 let kind =
@@ -1556,7 +1600,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15561600 if let FnKind :: Fn (
15571601 _,
15581602 _,
1559- FnSig { span : sig_span, header : FnHeader { ext : Extern :: Implicit , .. } , .. } ,
1603+ FnSig { span : sig_span, header : FnHeader { ext : Extern :: Implicit ( _ ) , .. } , .. } ,
15601604 _,
15611605 _,
15621606 _,
0 commit comments