Skip to content

Commit c539890

Browse files
committed
forbid tail calling intrinsics
1 parent 4b55fe1 commit c539890

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

compiler/rustc_mir_build/src/check_tail_calls.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
8989
self.report_op(ty, args, fn_span, expr);
9090
}
9191

92-
// Closures in thir look something akin to
93-
// `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}`
94-
// So we have to check for them in this weird way...
9592
if let &ty::FnDef(did, args) = ty.kind() {
93+
// Closures in thir look something akin to
94+
// `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}`
95+
// So we have to check for them in this weird way...
9696
let parent = self.tcx.parent(did);
9797
if self.tcx.fn_trait_kind_from_def_id(parent).is_some()
9898
&& args.first().and_then(|arg| arg.as_type()).is_some_and(Ty::is_closure)
@@ -103,6 +103,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
103103
// skip them, producing an error about calling a closure is enough.
104104
return;
105105
};
106+
107+
if self.tcx.intrinsic(did).is_some() {
108+
self.report_calling_intrinsic(expr);
109+
}
106110
}
107111

108112
// Erase regions since tail calls don't care about lifetimes
@@ -280,6 +284,16 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
280284
self.found_errors = Err(err);
281285
}
282286

287+
fn report_calling_intrinsic(&mut self, expr: &Expr<'_>) {
288+
let err = self
289+
.tcx
290+
.dcx()
291+
.struct_span_err(expr.span, "tail calling intrinsics is not allowed")
292+
.emit();
293+
294+
self.found_errors = Err(err);
295+
}
296+
283297
fn report_abi_mismatch(&mut self, sp: Span, caller_abi: ExternAbi, callee_abi: ExternAbi) {
284298
let err = self
285299
.tcx
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(explicit_tail_calls, core_intrinsics)]
2+
#![expect(incomplete_features, internal_features)]
3+
4+
fn trans((): ()) {
5+
unsafe { become std::mem::transmute(()) } //~ error: tail calling intrinsics is not allowed
6+
7+
}
8+
9+
fn cats(x: u64) -> u32 {
10+
become std::intrinsics::ctlz(x) //~ error: tail calling intrinsics is not allowed
11+
}
12+
13+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: tail calling intrinsics is not allowed
2+
--> $DIR/intrinsics.rs:5:14
3+
|
4+
LL | unsafe { become std::mem::transmute(()) }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: tail calling intrinsics is not allowed
8+
--> $DIR/intrinsics.rs:10:5
9+
|
10+
LL | become std::intrinsics::ctlz(x)
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)