11use std:: iter;
22
3- use rustc_abi:: ExternAbi ;
3+ use rustc_abi:: CanonAbi ;
44use rustc_ast:: util:: parser:: ExprPrecedence ;
55use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , StashKey } ;
66use rustc_hir:: def:: { self , CtorKind , Namespace , Res } ;
@@ -16,6 +16,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
1616use rustc_middle:: { bug, span_bug} ;
1717use rustc_span:: def_id:: LocalDefId ;
1818use rustc_span:: { Span , sym} ;
19+ use rustc_target:: spec:: { AbiMap , AbiMapping } ;
1920use rustc_trait_selection:: error_reporting:: traits:: DefIdOrName ;
2021use rustc_trait_selection:: infer:: InferCtxtExt as _;
2122use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
@@ -84,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8485 while result. is_none ( ) && autoderef. next ( ) . is_some ( ) {
8586 result = self . try_overloaded_call_step ( call_expr, callee_expr, arg_exprs, & autoderef) ;
8687 }
87- self . check_call_custom_abi ( autoderef. final_ty ( false ) , call_expr. span ) ;
88+ self . check_call_abi ( autoderef. final_ty ( false ) , call_expr. span ) ;
8889 self . register_predicates ( autoderef. into_obligations ( ) ) ;
8990
9091 let output = match result {
@@ -137,19 +138,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137138 output
138139 }
139140
140- /// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`.
141- ///
142- /// These functions have a calling convention that is unknown to rust, hence it cannot generate
143- /// code for the call. The only way to execute such a function is via inline assembly.
144- fn check_call_custom_abi ( & self , callee_ty : Ty < ' tcx > , span : Span ) {
141+ fn check_call_abi ( & self , callee_ty : Ty < ' tcx > , span : Span ) {
145142 let abi = match callee_ty. kind ( ) {
146143 ty:: FnDef ( def_id, _) => self . tcx . fn_sig ( def_id) . skip_binder ( ) . skip_binder ( ) . abi ,
147144 ty:: FnPtr ( _, header) => header. abi ,
148145 _ => return ,
149146 } ;
150147
151- if let ExternAbi :: Custom = abi {
152- self . tcx . dcx ( ) . emit_err ( errors:: AbiCustomCall { span } ) ;
148+ match AbiMap :: from_target ( & self . sess ( ) . target ) . canonize_abi ( abi, false ) {
149+ AbiMapping :: Direct ( canon_abi) | AbiMapping :: Deprecated ( canon_abi) => {
150+ if !Self :: can_be_called_with_call_expr ( canon_abi) {
151+ let err = crate :: errors:: AbiCannotBeCalled { span, abi } ;
152+ self . tcx . dcx ( ) . emit_err ( err) ;
153+ }
154+ }
155+ AbiMapping :: Invalid => {
156+ // The ABI is invalid for the target: ignore.
157+ }
158+ }
159+ }
160+
161+ /// Can a function with this ABI be called with a rust call expression?
162+ ///
163+ /// Some ABIs cannot be called from rust, either because rust does not know how to generate
164+ /// code for the call, or because a call does not semantically make sense.
165+ pub ( crate ) fn can_be_called_with_call_expr ( abi : CanonAbi ) -> bool {
166+ match abi {
167+ // Rust doesn't know how to call functions with this ABI.
168+ CanonAbi :: Custom => false ,
169+
170+ // These is an entry point for the host, and cannot be called on the GPU.
171+ CanonAbi :: GpuKernel => false ,
172+
173+ // The interrupt ABIs should only be called by the CPU. They have complex
174+ // pre- and postconditions, and can use non-standard instructions like `iret` on x86.
175+ CanonAbi :: Interrupt ( _) => false ,
176+
177+ CanonAbi :: C
178+ | CanonAbi :: Rust
179+ | CanonAbi :: RustCold
180+ | CanonAbi :: Arm ( _)
181+ | CanonAbi :: X86 ( _) => true ,
153182 }
154183 }
155184
0 commit comments