forbid tail calling intrinsics
This commit is contained in:
@@ -89,10 +89,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
|||||||
self.report_op(ty, args, fn_span, expr);
|
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() {
|
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);
|
let parent = self.tcx.parent(did);
|
||||||
if self.tcx.fn_trait_kind_from_def_id(parent).is_some()
|
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)
|
&& 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.
|
// skip them, producing an error about calling a closure is enough.
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if self.tcx.intrinsic(did).is_some() {
|
||||||
|
self.report_calling_intrinsic(expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erase regions since tail calls don't care about lifetimes
|
// Erase regions since tail calls don't care about lifetimes
|
||||||
@@ -280,6 +284,16 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
|||||||
self.found_errors = Err(err);
|
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) {
|
fn report_abi_mismatch(&mut self, sp: Span, caller_abi: ExternAbi, callee_abi: ExternAbi) {
|
||||||
let err = self
|
let err = self
|
||||||
.tcx
|
.tcx
|
||||||
|
|||||||
13
tests/ui/explicit-tail-calls/intrinsics.rs
Normal file
13
tests/ui/explicit-tail-calls/intrinsics.rs
Normal file
@@ -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() {}
|
||||||
14
tests/ui/explicit-tail-calls/intrinsics.stderr
Normal file
14
tests/ui/explicit-tail-calls/intrinsics.stderr
Normal file
@@ -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
|
||||||
|
|
||||||
Reference in New Issue
Block a user