about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/check_tail_calls.rs20
-rw-r--r--tests/ui/explicit-tail-calls/intrinsics.rs13
-rw-r--r--tests/ui/explicit-tail-calls/intrinsics.stderr14
3 files changed, 44 insertions, 3 deletions
diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs
index 18db8c1debb..6ed100899d8 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 00000000000..6fc521fa27d
--- /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 00000000000..b012e3629dd
--- /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
+