Skip to content

Commit 03b0436

Browse files
committed
error on calls to ABIs that cannot be called
1 parent d9ca9bd commit 03b0436

13 files changed

+845
-319
lines changed

compiler/rustc_hir_typeck/messages.ftl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
hir_typeck_abi_custom_call =
2-
functions with the `"custom"` ABI cannot be called
3-
.note = an `extern "custom"` function can only be called from within inline assembly
1+
hir_typeck_abi_cannot_be_called =
2+
functions with the `{$abi}` ABI cannot be called
3+
.note = an `extern {$abi}` function can only be called using inline assembly
44
55
hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
66

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::iter;
22

3-
use rustc_abi::ExternAbi;
3+
use rustc_abi::CanonAbi;
44
use rustc_ast::util::parser::ExprPrecedence;
55
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
66
use rustc_hir::def::{self, CtorKind, Namespace, Res};
@@ -16,6 +16,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
1616
use rustc_middle::{bug, span_bug};
1717
use rustc_span::def_id::LocalDefId;
1818
use rustc_span::{Span, sym};
19+
use rustc_target::spec::{AbiMap, AbiMapping};
1920
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
2021
use rustc_trait_selection::infer::InferCtxtExt as _;
2122
use 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

compiler/rustc_hir_typeck/src/errors.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::borrow::Cow;
44

5+
use rustc_abi::ExternAbi;
56
use rustc_ast::Label;
67
use rustc_errors::codes::*;
78
use rustc_errors::{
@@ -1165,8 +1166,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm {
11651166
}
11661167

11671168
#[derive(Diagnostic)]
1168-
#[diag(hir_typeck_abi_custom_call)]
1169-
pub(crate) struct AbiCustomCall {
1169+
#[diag(hir_typeck_abi_cannot_be_called)]
1170+
pub(crate) struct AbiCannotBeCalled {
11701171
#[primary_span]
1172+
#[note]
11711173
pub span: Span,
1174+
pub abi: ExternAbi,
11721175
}

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//!
66
//! See [`rustc_hir_analysis::check`] for more context on type checking in general.
77
8-
use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx};
8+
use rustc_abi::{FIRST_VARIANT, FieldIdx};
99
use rustc_ast::util::parser::ExprPrecedence;
1010
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1111
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -34,6 +34,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
3434
use rustc_span::hygiene::DesugaringKind;
3535
use rustc_span::source_map::Spanned;
3636
use rustc_span::{Ident, Span, Symbol, kw, sym};
37+
use rustc_target::spec::{AbiMap, AbiMapping};
3738
use rustc_trait_selection::infer::InferCtxtExt;
3839
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
3940
use tracing::{debug, instrument, trace};
@@ -1651,12 +1652,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16511652
Some(method.def_id),
16521653
);
16531654

1654-
// Functions of type `extern "custom" fn(/* ... */)` cannot be called using
1655-
// `ExprKind::MethodCall`. These functions have a calling convention that is
1656-
// unknown to rust, hence it cannot generate code for the call. The only way
1657-
// to execute such a function is via inline assembly.
1658-
if let ExternAbi::Custom = method.sig.abi {
1659-
self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span });
1655+
match AbiMap::from_target(&self.sess().target).canonize_abi(method.sig.abi, false) {
1656+
AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => {
1657+
if !Self::can_be_called_with_call_expr(canon_abi) {
1658+
self.tcx.dcx().emit_err(crate::errors::AbiCannotBeCalled {
1659+
span: expr.span,
1660+
abi: method.sig.abi,
1661+
});
1662+
}
1663+
}
1664+
AbiMapping::Invalid => { /* ignore */ }
16601665
}
16611666

16621667
method.sig.output()

tests/ui/abi/bad-custom.stderr

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,42 +248,84 @@ LL | extern "custom" fn negate(a: i64) -> i64 {
248248
error: functions with the `"custom"` ABI cannot be called
249249
--> $DIR/bad-custom.rs:75:14
250250
|
251+
LL | unsafe { f(x) }
252+
| ^^^^
253+
|
254+
note: an `extern "custom"` function can only be called using inline assembly
255+
--> $DIR/bad-custom.rs:75:14
256+
|
251257
LL | unsafe { f(x) }
252258
| ^^^^
253259

254260
error: functions with the `"custom"` ABI cannot be called
255261
--> $DIR/bad-custom.rs:80:14
256262
|
263+
LL | unsafe { f(x) }
264+
| ^^^^
265+
|
266+
note: an `extern "custom"` function can only be called using inline assembly
267+
--> $DIR/bad-custom.rs:80:14
268+
|
257269
LL | unsafe { f(x) }
258270
| ^^^^
259271

260272
error: functions with the `"custom"` ABI cannot be called
261273
--> $DIR/bad-custom.rs:87:14
262274
|
275+
LL | unsafe { f(x) }
276+
| ^^^^
277+
|
278+
note: an `extern "custom"` function can only be called using inline assembly
279+
--> $DIR/bad-custom.rs:87:14
280+
|
263281
LL | unsafe { f(x) }
264282
| ^^^^
265283

266284
error: functions with the `"custom"` ABI cannot be called
267285
--> $DIR/bad-custom.rs:109:20
268286
|
287+
LL | assert_eq!(double(21), 42);
288+
| ^^^^^^^^^^
289+
|
290+
note: an `extern "custom"` function can only be called using inline assembly
291+
--> $DIR/bad-custom.rs:109:20
292+
|
269293
LL | assert_eq!(double(21), 42);
270294
| ^^^^^^^^^^
271295

272296
error: functions with the `"custom"` ABI cannot be called
273297
--> $DIR/bad-custom.rs:112:29
274298
|
299+
LL | assert_eq!(unsafe { increment(41) }, 42);
300+
| ^^^^^^^^^^^^^
301+
|
302+
note: an `extern "custom"` function can only be called using inline assembly
303+
--> $DIR/bad-custom.rs:112:29
304+
|
275305
LL | assert_eq!(unsafe { increment(41) }, 42);
276306
| ^^^^^^^^^^^^^
277307

278308
error: functions with the `"custom"` ABI cannot be called
279309
--> $DIR/bad-custom.rs:115:17
280310
|
311+
LL | assert!(Thing(41).is_even());
312+
| ^^^^^^^^^^^^^^^^^^^
313+
|
314+
note: an `extern "custom"` function can only be called using inline assembly
315+
--> $DIR/bad-custom.rs:115:17
316+
|
281317
LL | assert!(Thing(41).is_even());
282318
| ^^^^^^^^^^^^^^^^^^^
283319

284320
error: functions with the `"custom"` ABI cannot be called
285321
--> $DIR/bad-custom.rs:118:20
286322
|
323+
LL | assert_eq!(Thing::bitwise_not(42), !42);
324+
| ^^^^^^^^^^^^^^^^^^^^^^
325+
|
326+
note: an `extern "custom"` function can only be called using inline assembly
327+
--> $DIR/bad-custom.rs:118:20
328+
|
287329
LL | assert_eq!(Thing::bitwise_not(42), !42);
288330
| ^^^^^^^^^^^^^^^^^^^^^^
289331

0 commit comments

Comments
 (0)