diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 18db8c1debb14..6ed100899d8c5 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -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 diff --git a/tests/ui/explicit-tail-calls/intrinsics.rs b/tests/ui/explicit-tail-calls/intrinsics.rs new file mode 100644 index 0000000000000..6fc521fa27d18 --- /dev/null +++ b/tests/ui/explicit-tail-calls/intrinsics.rs @@ -0,0 +1,13 @@ +#![feature(explicit_tail_calls, core_intrinsics)] +#![expect(incomplete_features, internal_features)] + +fn trans((): ()) { + unsafe { become std::mem::transmute(()) } //~ error: tail calling intrinsics is not allowed + +} + +fn cats(x: u64) -> u32 { + become std::intrinsics::ctlz(x) //~ error: tail calling intrinsics is not allowed +} + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/intrinsics.stderr b/tests/ui/explicit-tail-calls/intrinsics.stderr new file mode 100644 index 0000000000000..b012e3629ddee --- /dev/null +++ b/tests/ui/explicit-tail-calls/intrinsics.stderr @@ -0,0 +1,14 @@ +error: tail calling intrinsics is not allowed + --> $DIR/intrinsics.rs:5:14 + | +LL | unsafe { become std::mem::transmute(()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: tail calling intrinsics is not allowed + --> $DIR/intrinsics.rs:10:5 + | +LL | become std::intrinsics::ctlz(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +