@@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
2121use std:: str:: FromStr ;
2222
2323use itertools:: { Either , Itertools } ;
24- use rustc_abi:: ExternAbi ;
24+ use rustc_abi:: { CanonAbi , ExternAbi , InterruptKind } ;
2525use rustc_ast:: ptr:: P ;
2626use rustc_ast:: visit:: { AssocCtxt , BoundKind , FnCtxt , FnKind , Visitor , walk_list} ;
2727use rustc_ast:: * ;
@@ -37,6 +37,7 @@ use rustc_session::lint::builtin::{
3737} ;
3838use rustc_session:: lint:: { BuiltinLintDiag , LintBuffer } ;
3939use rustc_span:: { Ident , Span , kw, sym} ;
40+ use rustc_target:: spec:: { AbiMap , AbiMapping } ;
4041use thin_vec:: thin_vec;
4142
4243use crate :: errors:: { self , TildeConstReason } ;
@@ -379,46 +380,94 @@ impl<'a> AstValidator<'a> {
379380 }
380381 }
381382
382- /// An `extern "custom"` function must be unsafe, and must not have any parameters or return
383- /// type.
384- fn check_custom_abi ( & self , ctxt : FnCtxt , ident : & Ident , sig : & FnSig ) {
383+ /// Check that this function does not violate the constraints of its ABI.
384+ fn check_abi ( & self , abi : ExternAbi , ctxt : FnCtxt , ident : & Ident , sig : & FnSig ) {
385+ match AbiMap :: from_target ( & self . sess . target ) . canonize_abi ( abi, false ) {
386+ AbiMapping :: Direct ( canon_abi) | AbiMapping :: Deprecated ( canon_abi) => {
387+ match canon_abi {
388+ CanonAbi :: C
389+ | CanonAbi :: Rust
390+ | CanonAbi :: RustCold
391+ | CanonAbi :: Arm ( _)
392+ | CanonAbi :: GpuKernel
393+ | CanonAbi :: X86 ( _) => { /* nothing to check */ }
394+
395+ CanonAbi :: Custom => {
396+ // An `extern "custom"` function must be unsafe.
397+ self . check_abi_is_unsafe ( abi, ctxt, sig) ;
398+
399+ // An `extern "custom"` function cannot be `async` and/or `gen`.
400+ self . check_abi_is_not_coroutine ( abi, sig) ;
401+
402+ // An `extern "custom"` function must have type `fn()`.
403+ self . check_abi_no_params_or_return ( abi, ident, sig) ;
404+ }
405+
406+ CanonAbi :: Interrupt ( interrupt_kind) => {
407+ // An interrupt handler cannot be `async` and/or `gen`.
408+ self . check_abi_is_not_coroutine ( abi, sig) ;
409+
410+ if let InterruptKind :: X86 = interrupt_kind {
411+ // "x86-interrupt" is special because it does have arguments.
412+ // FIXME(workingjubilee): properly lint on acceptable input types.
413+ if let FnRetTy :: Ty ( ref ret_ty) = sig. decl . output {
414+ self . dcx ( ) . emit_err ( errors:: AbiMustNotHaveReturnType {
415+ span : ret_ty. span ,
416+ abi,
417+ } ) ;
418+ }
419+ } else {
420+ // An `extern "interrupt"` function must have type `fn()`.
421+ self . check_abi_no_params_or_return ( abi, ident, sig) ;
422+ }
423+ }
424+ }
425+ }
426+ AbiMapping :: Invalid => { /* ignore */ }
427+ }
428+ }
429+
430+ fn check_abi_is_unsafe ( & self , abi : ExternAbi , ctxt : FnCtxt , sig : & FnSig ) {
385431 let dcx = self . dcx ( ) ;
386432
387- // An `extern "custom"` function must be unsafe.
388433 match sig. header . safety {
389434 Safety :: Unsafe ( _) => { /* all good */ }
390435 Safety :: Safe ( safe_span) => {
391- let safe_span =
392- self . sess . psess . source_map ( ) . span_until_non_whitespace ( safe_span. to ( sig. span ) ) ;
436+ let source_map = self . sess . psess . source_map ( ) ;
437+ let safe_span = source_map. span_until_non_whitespace ( safe_span. to ( sig. span ) ) ;
393438 dcx. emit_err ( errors:: AbiCustomSafeForeignFunction { span : sig. span , safe_span } ) ;
394439 }
395440 Safety :: Default => match ctxt {
396441 FnCtxt :: Foreign => { /* all good */ }
397442 FnCtxt :: Free | FnCtxt :: Assoc ( _) => {
398- self . dcx ( ) . emit_err ( errors:: AbiCustomSafeFunction {
443+ dcx. emit_err ( errors:: AbiCustomSafeFunction {
399444 span : sig. span ,
445+ abi,
400446 unsafe_span : sig. span . shrink_to_lo ( ) ,
401447 } ) ;
402448 }
403449 } ,
404450 }
451+ }
405452
406- // An `extern "custom"` function cannot be `async` and/or `gen`.
453+ fn check_abi_is_not_coroutine ( & self , abi : ExternAbi , sig : & FnSig ) {
407454 if let Some ( coroutine_kind) = sig. header . coroutine_kind {
408455 let coroutine_kind_span = self
409456 . sess
410457 . psess
411458 . source_map ( )
412459 . span_until_non_whitespace ( coroutine_kind. span ( ) . to ( sig. span ) ) ;
413460
414- self . dcx ( ) . emit_err ( errors:: AbiCustomCoroutine {
461+ self . dcx ( ) . emit_err ( errors:: AbiCannotBeCoroutine {
415462 span : sig. span ,
463+ abi,
416464 coroutine_kind_span,
417465 coroutine_kind_str : coroutine_kind. as_str ( ) ,
418466 } ) ;
419467 }
468+ }
420469
421- // An `extern "custom"` function must not have any parameters or return type.
470+ fn check_abi_no_params_or_return ( & self , abi : ExternAbi , ident : & Ident , sig : & FnSig ) {
422471 let mut spans: Vec < _ > = sig. decl . inputs . iter ( ) . map ( |p| p. span ) . collect ( ) ;
423472 if let FnRetTy :: Ty ( ref ret_ty) = sig. decl . output {
424473 spans. push ( ret_ty. span ) ;
@@ -429,11 +478,12 @@ impl<'a> AstValidator<'a> {
429478 let suggestion_span = header_span. shrink_to_hi ( ) . to ( sig. decl . output . span ( ) ) ;
430479 let padding = if header_span. is_empty ( ) { "" } else { " " } ;
431480
432- self . dcx ( ) . emit_err ( errors:: AbiCustomInvalidSignature {
481+ self . dcx ( ) . emit_err ( errors:: AbiMustNotHaveParametersOrReturnType {
433482 spans,
434483 symbol : ident. name ,
435484 suggestion_span,
436485 padding,
486+ abi,
437487 } ) ;
438488 }
439489 }
@@ -1215,9 +1265,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12151265 self . check_foreign_fn_bodyless ( * ident, body. as_deref ( ) ) ;
12161266 self . check_foreign_fn_headerless ( sig. header ) ;
12171267 self . check_foreign_item_ascii_only ( * ident) ;
1218- if self . extern_mod_abi == Some ( ExternAbi :: Custom ) {
1219- self . check_custom_abi ( FnCtxt :: Foreign , ident, sig) ;
1220- }
1268+ self . check_abi (
1269+ self . extern_mod_abi . unwrap_or ( ExternAbi :: FALLBACK ) ,
1270+ FnCtxt :: Foreign ,
1271+ ident,
1272+ sig,
1273+ ) ;
12211274 }
12221275 ForeignItemKind :: TyAlias ( box TyAlias {
12231276 defaultness,
@@ -1427,9 +1480,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14271480
14281481 if let FnKind :: Fn ( ctxt, _, fun) = fk
14291482 && let Extern :: Explicit ( str_lit, _) = fun. sig . header . ext
1430- && let Ok ( ExternAbi :: Custom ) = ExternAbi :: from_str ( str_lit. symbol . as_str ( ) )
1483+ && let Ok ( abi ) = ExternAbi :: from_str ( str_lit. symbol . as_str ( ) )
14311484 {
1432- self . check_custom_abi ( ctxt, & fun. ident , & fun. sig ) ;
1485+ self . check_abi ( abi , ctxt, & fun. ident , & fun. sig ) ;
14331486 }
14341487
14351488 self . check_c_variadic_type ( fk) ;
0 commit comments