1
1
use std:: iter;
2
2
3
- use rustc_abi:: ExternAbi ;
3
+ use rustc_abi:: CanonAbi ;
4
4
use rustc_ast:: util:: parser:: ExprPrecedence ;
5
5
use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , StashKey } ;
6
6
use rustc_hir:: def:: { self , CtorKind , Namespace , Res } ;
@@ -16,6 +16,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
16
16
use rustc_middle:: { bug, span_bug} ;
17
17
use rustc_span:: def_id:: LocalDefId ;
18
18
use rustc_span:: { Span , sym} ;
19
+ use rustc_target:: spec:: { AbiMap , AbiMapping } ;
19
20
use rustc_trait_selection:: error_reporting:: traits:: DefIdOrName ;
20
21
use rustc_trait_selection:: infer:: InferCtxtExt as _;
21
22
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
@@ -84,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
84
85
while result. is_none ( ) && autoderef. next ( ) . is_some ( ) {
85
86
result = self . try_overloaded_call_step ( call_expr, callee_expr, arg_exprs, & autoderef) ;
86
87
}
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 ) ;
88
89
self . register_predicates ( autoderef. into_obligations ( ) ) ;
89
90
90
91
let output = match result {
@@ -137,19 +138,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137
138
output
138
139
}
139
140
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 ) {
145
142
let abi = match callee_ty. kind ( ) {
146
143
ty:: FnDef ( def_id, _) => self . tcx . fn_sig ( def_id) . skip_binder ( ) . skip_binder ( ) . abi ,
147
144
ty:: FnPtr ( _, header) => header. abi ,
148
145
_ => return ,
149
146
} ;
150
147
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 ,
153
182
}
154
183
}
155
184
0 commit comments