@@ -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