fix tail call checks wrt #[track_caller]
only check the caller + disallow caller having the attr.
This commit is contained in:
parent
99768c80a1
commit
992e3b4f03
6 changed files with 92 additions and 34 deletions
|
@ -131,11 +131,24 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// `#[track_caller]` affects the ABI of a function (by adding a location argument),
|
||||||
|
// so a `track_caller` can only tail call other `track_caller` functions.
|
||||||
|
//
|
||||||
|
// The issue is however that we can't know if a function is `track_caller` or not at
|
||||||
|
// this point (THIR can be polymorphic, we may have an unresolved trait function).
|
||||||
|
// We could only allow functions that we *can* resolve and *are* `track_caller`,
|
||||||
|
// but that would turn changing `track_caller`-ness into a breaking change,
|
||||||
|
// which is probably undesirable.
|
||||||
|
//
|
||||||
|
// Also note that we don't check callee's `track_caller`-ness at all, mostly for the
|
||||||
|
// reasons above, but also because we can always tailcall the shim we'd generate for
|
||||||
|
// coercing the function to an `fn()` pointer. (although in that case the tailcall is
|
||||||
|
// basically useless -- the shim calls the actual function, so tailcalling the shim is
|
||||||
|
// equivalent to calling the function)
|
||||||
let caller_needs_location = self.needs_location(self.caller_ty);
|
let caller_needs_location = self.needs_location(self.caller_ty);
|
||||||
let callee_needs_location = self.needs_location(ty);
|
|
||||||
|
|
||||||
if caller_needs_location != callee_needs_location {
|
if caller_needs_location {
|
||||||
self.report_track_caller_mismatch(expr.span, caller_needs_location);
|
self.report_track_caller_caller(expr.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +162,9 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if function of type `ty` needs location argument
|
/// Returns true if function of type `ty` needs location argument
|
||||||
/// (i.e. if a function is marked as `#[track_caller]`)
|
/// (i.e. if a function is marked as `#[track_caller]`).
|
||||||
|
///
|
||||||
|
/// Panics if the function's instance can't be immediately resolved.
|
||||||
fn needs_location(&self, ty: Ty<'tcx>) -> bool {
|
fn needs_location(&self, ty: Ty<'tcx>) -> bool {
|
||||||
if let &ty::FnDef(did, substs) = ty.kind() {
|
if let &ty::FnDef(did, substs) = ty.kind() {
|
||||||
let instance =
|
let instance =
|
||||||
|
@ -292,25 +307,15 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
||||||
self.found_errors = Err(err);
|
self.found_errors = Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_track_caller_mismatch(&mut self, sp: Span, caller_needs_location: bool) {
|
fn report_track_caller_caller(&mut self, sp: Span) {
|
||||||
let err = match caller_needs_location {
|
let err = self
|
||||||
true => self
|
|
||||||
.tcx
|
.tcx
|
||||||
.dcx()
|
.dcx()
|
||||||
.struct_span_err(
|
.struct_span_err(
|
||||||
sp,
|
sp,
|
||||||
"a function marked with `#[track_caller]` cannot tail-call one that is not",
|
"a function marked with `#[track_caller]` cannot perform a tail-call",
|
||||||
)
|
)
|
||||||
.emit(),
|
.emit();
|
||||||
false => self
|
|
||||||
.tcx
|
|
||||||
.dcx()
|
|
||||||
.struct_span_err(
|
|
||||||
sp,
|
|
||||||
"a function mot marked with `#[track_caller]` cannot tail-call one that is",
|
|
||||||
)
|
|
||||||
.emit(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.found_errors = Err(err);
|
self.found_errors = Err(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
//@ known-bug: #134336
|
|
||||||
#![expect(incomplete_features)]
|
|
||||||
#![feature(explicit_tail_calls)]
|
|
||||||
|
|
||||||
trait Tr {
|
|
||||||
fn f();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn g<T: Tr>() {
|
|
||||||
become T::f();
|
|
||||||
}
|
|
19
tests/ui/explicit-tail-calls/become-trait-fn.rs
Normal file
19
tests/ui/explicit-tail-calls/become-trait-fn.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// regression test for <https://github.com/rust-lang/rust/issues/134336>
|
||||||
|
// this previously caused an ICE, because we would compare `#[track_caller]` of
|
||||||
|
// the callee and the caller (in tailcalls specifically), leading to a problem
|
||||||
|
// since `T::f`'s instance can't be resolved (we do not know if the function is
|
||||||
|
// or isn't marked with `#[track_caller]`!)
|
||||||
|
//
|
||||||
|
//@ check-pass
|
||||||
|
#![expect(incomplete_features)]
|
||||||
|
#![feature(explicit_tail_calls)]
|
||||||
|
|
||||||
|
trait Tr {
|
||||||
|
fn f();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g<T: Tr>() {
|
||||||
|
become T::f();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
15
tests/ui/explicit-tail-calls/callee_is_track_caller.rs
Normal file
15
tests/ui/explicit-tail-calls/callee_is_track_caller.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//@ check-pass
|
||||||
|
// FIXME(explicit_tail_calls): make this run-pass, once tail calls are properly implemented
|
||||||
|
#![expect(incomplete_features)]
|
||||||
|
#![feature(explicit_tail_calls)]
|
||||||
|
|
||||||
|
fn a(x: u32) -> u32 {
|
||||||
|
become b(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn b(x: u32) -> u32 { x + 42 }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(a(12), 54);
|
||||||
|
}
|
16
tests/ui/explicit-tail-calls/caller_is_track_caller.rs
Normal file
16
tests/ui/explicit-tail-calls/caller_is_track_caller.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#![expect(incomplete_features)]
|
||||||
|
#![feature(explicit_tail_calls)]
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn a() {
|
||||||
|
become b(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn c() {
|
||||||
|
become a(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
tests/ui/explicit-tail-calls/caller_is_track_caller.stderr
Normal file
14
tests/ui/explicit-tail-calls/caller_is_track_caller.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: a function marked with `#[track_caller]` cannot perform a tail-call
|
||||||
|
--> $DIR/caller_is_track_caller.rs:6:5
|
||||||
|
|
|
||||||
|
LL | become b();
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a function marked with `#[track_caller]` cannot perform a tail-call
|
||||||
|
--> $DIR/caller_is_track_caller.rs:13:5
|
||||||
|
|
|
||||||
|
LL | become a();
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue