@@ -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 } ;
@@ -365,46 +366,94 @@ impl<'a> AstValidator<'a> {
365366 }
366367 }
367368
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 this function does not violate the constraints of its ABI.
370+ fn check_abi ( & 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 . check_abi_is_unsafe ( abi, ctxt, sig) ;
384+
385+ // An `extern "custom"` function cannot be `async` and/or `gen`.
386+ self . check_abi_is_not_coroutine ( abi, sig) ;
387+
388+ // An `extern "custom"` function must have type `fn()`.
389+ self . check_abi_no_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 . check_abi_is_not_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 . check_abi_no_params_or_return ( abi, ident, sig) ;
408+ }
409+ }
410+ }
411+ }
412+ AbiMapping :: Invalid => { /* ignore */ }
413+ }
414+ }
415+
416+ fn check_abi_is_unsafe ( & self , abi : ExternAbi , ctxt : FnCtxt , sig : & FnSig ) {
371417 let dcx = self . dcx ( ) ;
372418
373- // An `extern "custom"` function must be unsafe.
374419 match sig. header . safety {
375420 Safety :: Unsafe ( _) => { /* all good */ }
376421 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 ) ) ;
379424 dcx. emit_err ( errors:: AbiCustomSafeForeignFunction { span : sig. span , safe_span } ) ;
380425 }
381426 Safety :: Default => match ctxt {
382427 FnCtxt :: Foreign => { /* all good */ }
383428 FnCtxt :: Free | FnCtxt :: Assoc ( _) => {
384- self . dcx ( ) . emit_err ( errors:: AbiCustomSafeFunction {
429+ dcx. emit_err ( errors:: AbiCustomSafeFunction {
385430 span : sig. span ,
431+ abi,
386432 unsafe_span : sig. span . shrink_to_lo ( ) ,
387433 } ) ;
388434 }
389435 } ,
390436 }
437+ }
391438
392- // An `extern "custom"` function cannot be `async` and/or `gen`.
439+ fn check_abi_is_not_coroutine ( & self , abi : ExternAbi , sig : & FnSig ) {
393440 if let Some ( coroutine_kind) = sig. header . coroutine_kind {
394441 let coroutine_kind_span = self
395442 . sess
396443 . psess
397444 . source_map ( )
398445 . span_until_non_whitespace ( coroutine_kind. span ( ) . to ( sig. span ) ) ;
399446
400- self . dcx ( ) . emit_err ( errors:: AbiCustomCoroutine {
447+ self . dcx ( ) . emit_err ( errors:: AbiCannotBeCoroutine {
401448 span : sig. span ,
449+ abi,
402450 coroutine_kind_span,
403451 coroutine_kind_str : coroutine_kind. as_str ( ) ,
404452 } ) ;
405453 }
454+ }
406455
407- // An `extern "custom"` function must not have any parameters or return type.
456+ fn check_abi_no_params_or_return ( & self , abi : ExternAbi , ident : & Ident , sig : & FnSig ) {
408457 let mut spans: Vec < _ > = sig. decl . inputs . iter ( ) . map ( |p| p. span ) . collect ( ) ;
409458 if let FnRetTy :: Ty ( ref ret_ty) = sig. decl . output {
410459 spans. push ( ret_ty. span ) ;
@@ -415,11 +464,12 @@ impl<'a> AstValidator<'a> {
415464 let suggestion_span = header_span. shrink_to_hi ( ) . to ( sig. decl . output . span ( ) ) ;
416465 let padding = if header_span. is_empty ( ) { "" } else { " " } ;
417466
418- self . dcx ( ) . emit_err ( errors:: AbiCustomInvalidSignature {
467+ self . dcx ( ) . emit_err ( errors:: AbiMustNotHaveParametersOrReturnType {
419468 spans,
420469 symbol : ident. name ,
421470 suggestion_span,
422471 padding,
472+ abi,
423473 } ) ;
424474 }
425475 }
@@ -1199,9 +1249,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11991249 self . check_foreign_fn_bodyless ( * ident, body. as_deref ( ) ) ;
12001250 self . check_foreign_fn_headerless ( sig. header ) ;
12011251 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_abi (
1253+ self . extern_mod_abi . unwrap_or ( ExternAbi :: FALLBACK ) ,
1254+ FnCtxt :: Foreign ,
1255+ ident,
1256+ sig,
1257+ ) ;
12051258 }
12061259 ForeignItemKind :: TyAlias ( box TyAlias {
12071260 defaultness,
@@ -1411,9 +1464,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14111464
14121465 if let FnKind :: Fn ( ctxt, _, fun) = fk
14131466 && 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 ( ) )
14151468 {
1416- self . check_custom_abi ( ctxt, & fun. ident , & fun. sig ) ;
1469+ self . check_abi ( abi , ctxt, & fun. ident , & fun. sig ) ;
14171470 }
14181471
14191472 self . check_c_variadic_type ( fk) ;
0 commit comments