Skip to content

Commit 8c73581

Browse files
Auto merge of #142597 - folkertdev:abi-cannot-be-called, r=<try>
error on calls to ABIs that cannot be called We recently added `extern "custom"`, which cannot be called using a rust call expression. But there are more ABIs that can't be called in that way, because the call does not semantically make sense. More details are in #140566 (comment) r? `@workingjubilee` try-job: x86_64-gnu-llvm-19-3
2 parents 9c4ff56 + a32d085 commit 8c73581

23 files changed

+1359
-209
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: 42 additions & 12 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, ExternAbi};
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,18 @@ 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+
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+
88100
self.register_predicates(autoderef.into_obligations());
89101

90102
let output = match result {
@@ -137,19 +149,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137149
output
138150
}
139151

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?
141153
///
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,
149178
};
150179

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);
153183
}
154184
}
155185

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::{
@@ -1159,8 +1160,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm {
11591160
}
11601161

11611162
#[derive(Diagnostic)]
1162-
#[diag(hir_typeck_abi_custom_call)]
1163-
pub(crate) struct AbiCustomCall {
1163+
#[diag(hir_typeck_abi_cannot_be_called)]
1164+
pub(crate) struct AbiCannotBeCalled {
11641165
#[primary_span]
1166+
#[note]
11651167
pub span: Span,
1168+
pub abi: ExternAbi,
11661169
}

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 2 additions & 8 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;
@@ -1650,13 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16501650
Some(method.def_id),
16511651
);
16521652

1653-
// Functions of type `extern "custom" fn(/* ... */)` cannot be called using
1654-
// `ExprKind::MethodCall`. These functions have a calling convention that is
1655-
// unknown to rust, hence it cannot generate code for the call. The only way
1656-
// to execute such a function is via inline assembly.
1657-
if let ExternAbi::Custom = method.sig.abi {
1658-
self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span });
1659-
}
1653+
self.check_call_abi(method.sig.abi, expr.span);
16601654

16611655
method.sig.output()
16621656
}

tests/codegen/naked-asan.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
1-
// Make sure we do not request sanitizers for naked functions.
1+
//@ add-core-stubs
2+
//@ needs-llvm-components: x86
3+
//@ compile-flags: --target x86_64-unknown-linux-gnu -Zsanitizer=address -Ctarget-feature=-crt-static
24

3-
//@ only-x86_64
4-
//@ needs-sanitizer-address
5-
//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static
5+
// Make sure we do not request sanitizers for naked functions.
66

77
#![crate_type = "lib"]
8+
#![feature(no_core)]
89
#![no_std]
10+
#![no_core]
911
#![feature(abi_x86_interrupt)]
1012

13+
extern crate minicore;
14+
use minicore::*;
15+
16+
#[no_mangle]
1117
pub fn caller() {
12-
page_fault_handler(1, 2);
18+
unsafe { asm!("call {}", sym page_fault_handler) }
1319
}
1420

15-
// CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]]
21+
// CHECK: declare x86_intrcc void @page_fault_handler(){{.*}}#[[ATTRS:[0-9]+]]
1622
#[unsafe(naked)]
1723
#[no_mangle]
18-
pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) {
19-
core::arch::naked_asm!("ud2")
24+
pub extern "x86-interrupt" fn page_fault_handler() {
25+
naked_asm!("ud2")
2026
}
2127

2228
// CHECK: #[[ATTRS]] =

tests/ui/abi/bad-custom.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,19 @@ unsafe extern "custom" {
7373

7474
fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
7575
unsafe { f(x) }
76-
//~^ ERROR functions with the `"custom"` ABI cannot be called
76+
//~^ ERROR functions with the "custom" ABI cannot be called
7777
}
7878

7979
fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
8080
unsafe { f(x) }
81-
//~^ ERROR functions with the `"custom"` ABI cannot be called
81+
//~^ ERROR functions with the "custom" ABI cannot be called
8282
}
8383

8484
type Custom = unsafe extern "custom" fn(i64) -> i64;
8585

8686
fn caller_alias(f: Custom, mut x: i64) -> i64 {
8787
unsafe { f(x) }
88-
//~^ ERROR functions with the `"custom"` ABI cannot be called
88+
//~^ ERROR functions with the "custom" ABI cannot be called
8989
}
9090

9191
#[unsafe(naked)]
@@ -107,15 +107,15 @@ fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() {
107107
pub fn main() {
108108
unsafe {
109109
assert_eq!(double(21), 42);
110-
//~^ ERROR functions with the `"custom"` ABI cannot be called
110+
//~^ ERROR functions with the "custom" ABI cannot be called
111111

112112
assert_eq!(unsafe { increment(41) }, 42);
113-
//~^ ERROR functions with the `"custom"` ABI cannot be called
113+
//~^ ERROR functions with the "custom" ABI cannot be called
114114

115115
assert!(Thing(41).is_even());
116-
//~^ ERROR functions with the `"custom"` ABI cannot be called
116+
//~^ ERROR functions with the "custom" ABI cannot be called
117117

118118
assert_eq!(Thing::bitwise_not(42), !42);
119-
//~^ ERROR functions with the `"custom"` ABI cannot be called
119+
//~^ ERROR functions with the "custom" ABI cannot be called
120120
}
121121
}

tests/ui/abi/bad-custom.stderr

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,43 +245,85 @@ LL + #[unsafe(naked)]
245245
LL | extern "custom" fn negate(a: i64) -> i64 {
246246
|
247247

248-
error: functions with the `"custom"` ABI cannot be called
248+
error: functions with the "custom" ABI cannot be called
249+
--> $DIR/bad-custom.rs:75:14
250+
|
251+
LL | unsafe { f(x) }
252+
| ^^^^
253+
|
254+
note: an `extern "custom"` function can only be called using inline assembly
249255
--> $DIR/bad-custom.rs:75:14
250256
|
251257
LL | unsafe { f(x) }
252258
| ^^^^
253259

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

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

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

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

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

284-
error: functions with the `"custom"` ABI cannot be called
320+
error: functions with the "custom" ABI cannot be called
321+
--> $DIR/bad-custom.rs:118:20
322+
|
323+
LL | assert_eq!(Thing::bitwise_not(42), !42);
324+
| ^^^^^^^^^^^^^^^^^^^^^^
325+
|
326+
note: an `extern "custom"` function can only be called using inline assembly
285327
--> $DIR/bad-custom.rs:118:20
286328
|
287329
LL | assert_eq!(Thing::bitwise_not(42), !42);

0 commit comments

Comments
 (0)