1
1
use std:: iter;
2
2
3
- use rustc_abi:: ExternAbi ;
3
+ use rustc_abi:: { CanonAbi , ExternAbi } ;
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,18 @@ 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
+
89
+ match autoderef. final_ty ( false ) . kind ( ) {
90
+ ty:: FnDef ( def_id, _) => {
91
+ let abi = self . tcx . fn_sig ( def_id) . skip_binder ( ) . skip_binder ( ) . abi ;
92
+ self . check_call_abi ( abi, call_expr. span ) ;
93
+ }
94
+ ty:: FnPtr ( _, header) => {
95
+ self . check_call_abi ( header. abi , call_expr. span ) ;
96
+ }
97
+ _ => { /* cannot have a non-rust abi */ }
98
+ }
99
+
88
100
self . register_predicates ( autoderef. into_obligations ( ) ) ;
89
101
90
102
let output = match result {
@@ -137,19 +149,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137
149
output
138
150
}
139
151
140
- /// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`.
152
+ /// Can a function with this ABI be called with a rust call expression?
141
153
///
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 ) {
145
- let abi = match callee_ty. kind ( ) {
146
- ty:: FnDef ( def_id, _) => self . tcx . fn_sig ( def_id) . skip_binder ( ) . skip_binder ( ) . abi ,
147
- ty:: FnPtr ( _, header) => header. abi ,
148
- _ => return ,
154
+ /// Some ABIs cannot be called from rust, either because rust does not know how to generate
155
+ /// code for the call, or because a call does not semantically make sense.
156
+ pub ( crate ) fn check_call_abi ( & self , abi : ExternAbi , span : Span ) {
157
+ let canon_abi = match AbiMap :: from_target ( & self . sess ( ) . target ) . canonize_abi ( abi, false ) {
158
+ AbiMapping :: Direct ( canon_abi) | AbiMapping :: Deprecated ( canon_abi) => canon_abi,
159
+ AbiMapping :: Invalid => return ,
160
+ } ;
161
+
162
+ let valid = match canon_abi {
163
+ // Rust doesn't know how to call functions with this ABI.
164
+ CanonAbi :: Custom => false ,
165
+
166
+ // These is an entry point for the host, and cannot be called on the GPU.
167
+ CanonAbi :: GpuKernel => false ,
168
+
169
+ // The interrupt ABIs should only be called by the CPU. They have complex
170
+ // pre- and postconditions, and can use non-standard instructions like `iret` on x86.
171
+ CanonAbi :: Interrupt ( _) => false ,
172
+
173
+ CanonAbi :: C
174
+ | CanonAbi :: Rust
175
+ | CanonAbi :: RustCold
176
+ | CanonAbi :: Arm ( _)
177
+ | CanonAbi :: X86 ( _) => true ,
149
178
} ;
150
179
151
- if let ExternAbi :: Custom = abi {
152
- self . tcx . dcx ( ) . emit_err ( errors:: AbiCustomCall { span } ) ;
180
+ if !valid {
181
+ let err = crate :: errors:: AbiCannotBeCalled { span, abi } ;
182
+ self . tcx . dcx ( ) . emit_err ( err) ;
153
183
}
154
184
}
155
185
0 commit comments