@@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
21
21
use std:: str:: FromStr ;
22
22
23
23
use itertools:: { Either , Itertools } ;
24
- use rustc_abi:: ExternAbi ;
24
+ use rustc_abi:: { CanonAbi , ExternAbi , InterruptKind } ;
25
25
use rustc_ast:: ptr:: P ;
26
26
use rustc_ast:: visit:: { AssocCtxt , BoundKind , FnCtxt , FnKind , Visitor , walk_list} ;
27
27
use rustc_ast:: * ;
@@ -37,6 +37,7 @@ use rustc_session::lint::builtin::{
37
37
} ;
38
38
use rustc_session:: lint:: { BuiltinLintDiag , LintBuffer } ;
39
39
use rustc_span:: { Ident , Span , kw, sym} ;
40
+ use rustc_target:: spec:: { AbiMap , AbiMapping } ;
40
41
use thin_vec:: thin_vec;
41
42
42
43
use crate :: errors:: { self , TildeConstReason } ;
@@ -365,46 +366,94 @@ impl<'a> AstValidator<'a> {
365
366
}
366
367
}
367
368
368
- /// An `extern "custom"` function must be unsafe, and must not have any parameters or return
369
- /// type.
370
- fn check_custom_abi ( & self , ctxt : FnCtxt , ident : & Ident , sig : & FnSig ) {
369
+ /// Check that the signature of this function does not violate the constraints of its ABI.
370
+ fn check_extern_fn_signature ( & self , abi : ExternAbi , ctxt : FnCtxt , ident : & Ident , sig : & FnSig ) {
371
+ match AbiMap :: from_target ( & self . sess . target ) . canonize_abi ( abi, false ) {
372
+ AbiMapping :: Direct ( canon_abi) | AbiMapping :: Deprecated ( canon_abi) => {
373
+ match canon_abi {
374
+ CanonAbi :: C
375
+ | CanonAbi :: Rust
376
+ | CanonAbi :: RustCold
377
+ | CanonAbi :: Arm ( _)
378
+ | CanonAbi :: GpuKernel
379
+ | CanonAbi :: X86 ( _) => { /* nothing to check */ }
380
+
381
+ CanonAbi :: Custom => {
382
+ // An `extern "custom"` function must be unsafe.
383
+ self . reject_safe_fn ( abi, ctxt, sig) ;
384
+
385
+ // An `extern "custom"` function cannot be `async` and/or `gen`.
386
+ self . reject_coroutine ( abi, sig) ;
387
+
388
+ // An `extern "custom"` function must have type `fn()`.
389
+ self . reject_params_or_return ( abi, ident, sig) ;
390
+ }
391
+
392
+ CanonAbi :: Interrupt ( interrupt_kind) => {
393
+ // An interrupt handler cannot be `async` and/or `gen`.
394
+ self . reject_coroutine ( abi, sig) ;
395
+
396
+ if let InterruptKind :: X86 = interrupt_kind {
397
+ // "x86-interrupt" is special because it does have arguments.
398
+ // FIXME(workingjubilee): properly lint on acceptable input types.
399
+ if let FnRetTy :: Ty ( ref ret_ty) = sig. decl . output {
400
+ self . dcx ( ) . emit_err ( errors:: AbiMustNotHaveReturnType {
401
+ span : ret_ty. span ,
402
+ abi,
403
+ } ) ;
404
+ }
405
+ } else {
406
+ // An `extern "interrupt"` function must have type `fn()`.
407
+ self . reject_params_or_return ( abi, ident, sig) ;
408
+ }
409
+ }
410
+ }
411
+ }
412
+ AbiMapping :: Invalid => { /* ignore */ }
413
+ }
414
+ }
415
+
416
+ fn reject_safe_fn ( & self , abi : ExternAbi , ctxt : FnCtxt , sig : & FnSig ) {
371
417
let dcx = self . dcx ( ) ;
372
418
373
- // An `extern "custom"` function must be unsafe.
374
419
match sig. header . safety {
375
420
Safety :: Unsafe ( _) => { /* all good */ }
376
421
Safety :: Safe ( safe_span) => {
377
- let safe_span =
378
- self . sess . psess . source_map ( ) . span_until_non_whitespace ( safe_span. to ( sig. span ) ) ;
422
+ let source_map = self . sess . psess . source_map ( ) ;
423
+ let safe_span = source_map. span_until_non_whitespace ( safe_span. to ( sig. span ) ) ;
379
424
dcx. emit_err ( errors:: AbiCustomSafeForeignFunction { span : sig. span , safe_span } ) ;
380
425
}
381
426
Safety :: Default => match ctxt {
382
427
FnCtxt :: Foreign => { /* all good */ }
383
428
FnCtxt :: Free | FnCtxt :: Assoc ( _) => {
384
- self . dcx ( ) . emit_err ( errors:: AbiCustomSafeFunction {
429
+ dcx. emit_err ( errors:: AbiCustomSafeFunction {
385
430
span : sig. span ,
431
+ abi,
386
432
unsafe_span : sig. span . shrink_to_lo ( ) ,
387
433
} ) ;
388
434
}
389
435
} ,
390
436
}
437
+ }
391
438
392
- // An `extern "custom"` function cannot be `async` and/or `gen`.
439
+ fn reject_coroutine ( & self , abi : ExternAbi , sig : & FnSig ) {
393
440
if let Some ( coroutine_kind) = sig. header . coroutine_kind {
394
441
let coroutine_kind_span = self
395
442
. sess
396
443
. psess
397
444
. source_map ( )
398
445
. span_until_non_whitespace ( coroutine_kind. span ( ) . to ( sig. span ) ) ;
399
446
400
- self . dcx ( ) . emit_err ( errors:: AbiCustomCoroutine {
447
+ self . dcx ( ) . emit_err ( errors:: AbiCannotBeCoroutine {
401
448
span : sig. span ,
449
+ abi,
402
450
coroutine_kind_span,
403
451
coroutine_kind_str : coroutine_kind. as_str ( ) ,
404
452
} ) ;
405
453
}
454
+ }
406
455
407
- // An `extern "custom"` function must not have any parameters or return type.
456
+ fn reject_params_or_return ( & self , abi : ExternAbi , ident : & Ident , sig : & FnSig ) {
408
457
let mut spans: Vec < _ > = sig. decl . inputs . iter ( ) . map ( |p| p. span ) . collect ( ) ;
409
458
if let FnRetTy :: Ty ( ref ret_ty) = sig. decl . output {
410
459
spans. push ( ret_ty. span ) ;
@@ -415,11 +464,12 @@ impl<'a> AstValidator<'a> {
415
464
let suggestion_span = header_span. shrink_to_hi ( ) . to ( sig. decl . output . span ( ) ) ;
416
465
let padding = if header_span. is_empty ( ) { "" } else { " " } ;
417
466
418
- self . dcx ( ) . emit_err ( errors:: AbiCustomInvalidSignature {
467
+ self . dcx ( ) . emit_err ( errors:: AbiMustNotHaveParametersOrReturnType {
419
468
spans,
420
469
symbol : ident. name ,
421
470
suggestion_span,
422
471
padding,
472
+ abi,
423
473
} ) ;
424
474
}
425
475
}
@@ -1199,9 +1249,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1199
1249
self . check_foreign_fn_bodyless ( * ident, body. as_deref ( ) ) ;
1200
1250
self . check_foreign_fn_headerless ( sig. header ) ;
1201
1251
self . check_foreign_item_ascii_only ( * ident) ;
1202
- if self . extern_mod_abi == Some ( ExternAbi :: Custom ) {
1203
- self . check_custom_abi ( FnCtxt :: Foreign , ident, sig) ;
1204
- }
1252
+ self . check_extern_fn_signature (
1253
+ self . extern_mod_abi . unwrap_or ( ExternAbi :: FALLBACK ) ,
1254
+ FnCtxt :: Foreign ,
1255
+ ident,
1256
+ sig,
1257
+ ) ;
1205
1258
}
1206
1259
ForeignItemKind :: TyAlias ( box TyAlias {
1207
1260
defaultness,
@@ -1411,9 +1464,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1411
1464
1412
1465
if let FnKind :: Fn ( ctxt, _, fun) = fk
1413
1466
&& let Extern :: Explicit ( str_lit, _) = fun. sig . header . ext
1414
- && let Ok ( ExternAbi :: Custom ) = ExternAbi :: from_str ( str_lit. symbol . as_str ( ) )
1467
+ && let Ok ( abi ) = ExternAbi :: from_str ( str_lit. symbol . as_str ( ) )
1415
1468
{
1416
- self . check_custom_abi ( ctxt, & fun. ident , & fun. sig ) ;
1469
+ self . check_extern_fn_signature ( abi , ctxt, & fun. ident , & fun. sig ) ;
1417
1470
}
1418
1471
1419
1472
self . check_c_variadic_type ( fk) ;
0 commit comments