@@ -13,7 +13,9 @@ use rustc_ast::walk_list;
13
13
use rustc_ast:: * ;
14
14
use rustc_ast_pretty:: pprust:: { self , State } ;
15
15
use 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
+ } ;
17
19
use rustc_parse:: validate_attr;
18
20
use rustc_session:: lint:: builtin:: {
19
21
DEPRECATED_WHERE_CLAUSE_LOCATION , MISSING_ABI , PATTERNS_IN_FNS_WITHOUT_BODY ,
@@ -476,22 +478,33 @@ impl<'a> AstValidator<'a> {
476
478
}
477
479
478
480
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
+ ) {
479
492
let source_map = self . session . source_map ( ) ;
480
493
let end = source_map. end_point ( sp) ;
481
494
let replace_span = if source_map. span_to_snippet ( end) . map ( |s| s == ";" ) . unwrap_or ( false ) {
482
495
end
483
496
} else {
484
497
sp. shrink_to_hi ( )
485
498
} ;
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 ( ) ;
495
508
}
496
509
497
510
fn check_impl_item_provided < T > ( & self , sp : Span , body : & Option < T > , ctx : & str , sugg : & str ) {
@@ -1191,8 +1204,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1191
1204
1192
1205
if body. is_none ( ) {
1193
1206
let msg = "free function without a body" ;
1194
- 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
+ ) ;
1195
1237
}
1238
+
1196
1239
self . visit_vis ( & item. vis ) ;
1197
1240
self . visit_ident ( item. ident ) ;
1198
1241
let kind =
0 commit comments