@@ -546,7 +546,13 @@ impl<'a> AstValidator<'a> {
546546 }
547547
548548 /// Check that the signature of this function does not violate the constraints of its ABI.
549- fn check_extern_fn_signature ( & self , abi : ExternAbi , ctxt : FnCtxt , ident : & Ident , sig : & FnSig ) {
549+ fn check_extern_fn_signature (
550+ & self ,
551+ abi : ExternAbi ,
552+ ctxt : FnCtxt ,
553+ opt_function_name : Option < & Ident > , // None for function pointers
554+ sig : & BorrowedFnSig < ' _ > ,
555+ ) {
550556 match AbiMap :: from_target ( & self . sess . target ) . canonize_abi ( abi, false ) {
551557 AbiMapping :: Direct ( canon_abi) | AbiMapping :: Deprecated ( canon_abi) => {
552558 match canon_abi {
@@ -569,13 +575,13 @@ impl<'a> AstValidator<'a> {
569575
570576 CanonAbi :: Custom => {
571577 // An `extern "custom"` function must be unsafe.
572- self . reject_safe_fn ( abi, ctxt, sig) ;
578+ self . reject_safe_fn ( abi, ctxt, sig, opt_function_name . is_none ( ) ) ;
573579
574580 // An `extern "custom"` function cannot be `async` and/or `gen`.
575581 self . reject_coroutine ( abi, sig) ;
576582
577583 // An `extern "custom"` function must have type `fn()`.
578- self . reject_params_or_return ( abi, ident , sig) ;
584+ self . reject_params_or_return ( abi, opt_function_name , sig) ;
579585 }
580586
581587 CanonAbi :: Interrupt ( interrupt_kind) => {
@@ -600,7 +606,7 @@ impl<'a> AstValidator<'a> {
600606 self . reject_return ( abi, sig) ;
601607 } else {
602608 // An `extern "interrupt"` function must have type `fn()`.
603- self . reject_params_or_return ( abi, ident , sig) ;
609+ self . reject_params_or_return ( abi, opt_function_name , sig) ;
604610 }
605611 }
606612 }
@@ -609,18 +615,27 @@ impl<'a> AstValidator<'a> {
609615 }
610616 }
611617
612- fn reject_safe_fn ( & self , abi : ExternAbi , ctxt : FnCtxt , sig : & FnSig ) {
618+ fn reject_safe_fn (
619+ & self ,
620+ abi : ExternAbi ,
621+ ctxt : FnCtxt ,
622+ sig : & BorrowedFnSig < ' _ > ,
623+ is_fn_ptr : bool ,
624+ ) {
613625 let dcx = self . dcx ( ) ;
614626
615627 match sig. header . safety {
616628 Safety :: Unsafe ( _) => { /* all good */ }
617629 Safety :: Safe ( safe_span) => {
618- let source_map = self . sess . psess . source_map ( ) ;
619- let safe_span = source_map. span_until_non_whitespace ( safe_span. to ( sig. span ) ) ;
620- dcx. emit_err ( diagnostics:: AbiCustomSafeForeignFunction {
621- span : sig. span ,
622- safe_span,
623- } ) ;
630+ // Function pointers already error when `safe` is used.
631+ if !is_fn_ptr {
632+ let source_map = self . sess . psess . source_map ( ) ;
633+ let safe_span = source_map. span_until_non_whitespace ( safe_span. to ( sig. span ) ) ;
634+ dcx. emit_err ( diagnostics:: AbiCustomSafeForeignFunction {
635+ span : sig. span ,
636+ safe_span,
637+ } ) ;
638+ }
624639 }
625640 Safety :: Default => match ctxt {
626641 FnCtxt :: Foreign => { /* all good */ }
@@ -635,7 +650,7 @@ impl<'a> AstValidator<'a> {
635650 }
636651 }
637652
638- fn reject_coroutine ( & self , abi : ExternAbi , sig : & FnSig ) {
653+ fn reject_coroutine ( & self , abi : ExternAbi , sig : & BorrowedFnSig < ' _ > ) {
639654 if let Some ( coroutine_kind) = sig. header . coroutine_kind {
640655 let coroutine_kind_span = self
641656 . sess
@@ -652,7 +667,7 @@ impl<'a> AstValidator<'a> {
652667 }
653668 }
654669
655- fn reject_return ( & self , abi : ExternAbi , sig : & FnSig ) {
670+ fn reject_return ( & self , abi : ExternAbi , sig : & BorrowedFnSig < ' _ > ) {
656671 if let FnRetTy :: Ty ( ref ret_ty) = sig. decl . output
657672 && match & ret_ty. kind {
658673 TyKind :: Never => false ,
@@ -664,29 +679,41 @@ impl<'a> AstValidator<'a> {
664679 }
665680 }
666681
667- fn reject_params_or_return ( & self , abi : ExternAbi , ident : & Ident , sig : & FnSig ) {
682+ fn reject_params_or_return (
683+ & self ,
684+ abi : ExternAbi ,
685+ opt_function_name : Option < & Ident > , // None for function pointers
686+ sig : & BorrowedFnSig < ' _ > ,
687+ ) {
668688 let mut spans: Vec < _ > = sig. decl . inputs . iter ( ) . map ( |p| p. span ) . collect ( ) ;
689+
690+ let allowed_return = |ret_ty : & Ty | match & ret_ty. kind {
691+ TyKind :: Never if abi != ExternAbi :: Custom => true ,
692+ TyKind :: Tup ( tup) if tup. is_empty ( ) => true ,
693+ _ => false ,
694+ } ;
695+
669696 if let FnRetTy :: Ty ( ref ret_ty) = sig. decl . output
670- && match & ret_ty. kind {
671- TyKind :: Never => false ,
672- TyKind :: Tup ( tup) if tup. is_empty ( ) => false ,
673- _ => true ,
674- }
697+ && !allowed_return ( ret_ty)
675698 {
676699 spans. push ( ret_ty. span ) ;
677700 }
678701
679702 if !spans. is_empty ( ) {
680- let header_span = sig. header_span ( ) ;
703+ let header_span = sig. header . span ( ) . unwrap_or ( sig . span . shrink_to_lo ( ) ) ;
681704 let suggestion_span = header_span. shrink_to_hi ( ) . to ( sig. decl . output . span ( ) ) ;
682705 let padding = if header_span. is_empty ( ) { "" } else { " " } ;
683706
684707 self . dcx ( ) . emit_err ( diagnostics:: AbiMustNotHaveParametersOrReturnType {
685708 spans,
686- symbol : ident. name ,
709+ abi,
710+
687711 suggestion_span,
688712 padding,
689- abi,
713+ symbol : match opt_function_name {
714+ Some ( ident) => format ! ( " {}" , ident. name) ,
715+ None => String :: new ( ) ,
716+ } ,
690717 } ) ;
691718 }
692719 }
@@ -717,8 +744,12 @@ impl<'a> AstValidator<'a> {
717744 }
718745
719746 fn check_fn_ptr_safety ( & self , span : Span , safety : Safety ) {
720- if matches ! ( safety, Safety :: Safe ( _) ) {
721- self . dcx ( ) . emit_err ( diagnostics:: InvalidSafetyOnFnPtr { span } ) ;
747+ if let Safety :: Safe ( safe_span) = safety {
748+ let remove_span = self . sess . source_map ( ) . span_until_non_whitespace ( span) ;
749+ self . dcx ( ) . emit_err ( diagnostics:: InvalidSafetyOnFnPtr {
750+ span : safe_span,
751+ safe_span : remove_span,
752+ } ) ;
722753 }
723754 }
724755
@@ -1138,6 +1169,24 @@ impl<'a> AstValidator<'a> {
11381169 if let Extern :: Implicit ( extern_span) = bfty. ext {
11391170 self . handle_missing_abi ( extern_span, ty. id ) ;
11401171 }
1172+
1173+ let ext = match bfty. ext {
1174+ Extern :: None => None ,
1175+ Extern :: Implicit ( _) => Some ( ExternAbi :: FALLBACK ) ,
1176+ Extern :: Explicit ( str_lit, _) => {
1177+ ExternAbi :: from_str ( str_lit. symbol . as_str ( ) ) . ok ( )
1178+ }
1179+ } ;
1180+
1181+ // Some ABIs impose special restrictions on the signature.
1182+ if let Some ( extern_abi) = ext {
1183+ self . check_extern_fn_signature (
1184+ extern_abi,
1185+ FnCtxt :: Free ,
1186+ None ,
1187+ & bfty. as_borrowed_fn_sig ( ) ,
1188+ ) ;
1189+ }
11411190 }
11421191 TyKind :: TraitObject ( bounds, ..) => {
11431192 let mut any_lifetime_bounds = false ;
@@ -1664,8 +1713,8 @@ impl Visitor<'_> for AstValidator<'_> {
16641713 self . check_extern_fn_signature (
16651714 self . extern_mod_abi . unwrap_or ( ExternAbi :: FALLBACK ) ,
16661715 FnCtxt :: Foreign ,
1667- ident,
1668- sig,
1716+ Some ( ident) ,
1717+ & sig. as_borrowed ( ) ,
16691718 ) ;
16701719
16711720 if let Some ( attr) = attr:: find_by_name ( fi. attrs ( ) , sym:: track_caller)
@@ -1870,7 +1919,12 @@ impl Visitor<'_> for AstValidator<'_> {
18701919
18711920 if let Some ( ( extern_abi, extern_abi_span) ) = ext {
18721921 // Some ABIs impose special restrictions on the signature.
1873- self . check_extern_fn_signature ( extern_abi, ctxt, & fun. ident , & fun. sig ) ;
1922+ self . check_extern_fn_signature (
1923+ extern_abi,
1924+ ctxt,
1925+ Some ( & fun. ident ) ,
1926+ & fun. sig . as_borrowed ( ) ,
1927+ ) ;
18741928
18751929 // #[track_caller] can only be used with the rust ABI.
18761930 if let Some ( attr) = attr:: find_by_name ( attrs, sym:: track_caller)
0 commit comments