Rollup merge of #144851 - WaffleLapkin:instrinsic-deny, r=compiler-errors,scottmcm

Forbid tail calling intrinsics

There is only one intrinsic that can be called on stable, as far as I can find, (`transmute`). And in general tail calling intrinsics doesn't make much sense.

Alternative to rust-lang/rust#144815 (and thus closes rust-lang/rust#144815)
Fixes https://github.com/rust-lang/rust/issues/144806

r? ``@scottmcm``
This commit is contained in:
Samuel Tardieu
2025-08-03 21:57:02 +02:00
committed by GitHub
3 changed files with 44 additions and 3 deletions

View File

@@ -89,10 +89,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
self.report_op(ty, args, fn_span, expr);
}
// Closures in thir look something akin to
// `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}`
// So we have to check for them in this weird way...
if let &ty::FnDef(did, args) = ty.kind() {
// Closures in thir look something akin to
// `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}`
// So we have to check for them in this weird way...
let parent = self.tcx.parent(did);
if self.tcx.fn_trait_kind_from_def_id(parent).is_some()
&& args.first().and_then(|arg| arg.as_type()).is_some_and(Ty::is_closure)
@@ -103,6 +103,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
// skip them, producing an error about calling a closure is enough.
return;
};
if self.tcx.intrinsic(did).is_some() {
self.report_calling_intrinsic(expr);
}
}
// Erase regions since tail calls don't care about lifetimes
@@ -280,6 +284,16 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
self.found_errors = Err(err);
}
fn report_calling_intrinsic(&mut self, expr: &Expr<'_>) {
let err = self
.tcx
.dcx()
.struct_span_err(expr.span, "tail calling intrinsics is not allowed")
.emit();
self.found_errors = Err(err);
}
fn report_abi_mismatch(&mut self, sp: Span, caller_abi: ExternAbi, callee_abi: ExternAbi) {
let err = self
.tcx