Skip to content

Commit 1c794b9

Browse files
authored
Rollup merge of #135973 - WaffleLapkin:tail-track-caller-fix, r=compiler-errors
fix tail call checks wrt `#[track_caller]` Only check the caller + disallow caller having the attribute. fixes #134336 r? `@compiler-errors` <sub>apparently there were no tests for `#[track_caller]` before... ooops</sub>
2 parents 550e035 + 992e3b4 commit 1c794b9

File tree

6 files changed

+92
-34
lines changed

6 files changed

+92
-34
lines changed

compiler/rustc_mir_build/src/check_tail_calls.rs

+28-23
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,24 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
132132
}
133133

134134
{
135+
// `#[track_caller]` affects the ABI of a function (by adding a location argument),
136+
// so a `track_caller` can only tail call other `track_caller` functions.
137+
//
138+
// The issue is however that we can't know if a function is `track_caller` or not at
139+
// this point (THIR can be polymorphic, we may have an unresolved trait function).
140+
// We could only allow functions that we *can* resolve and *are* `track_caller`,
141+
// but that would turn changing `track_caller`-ness into a breaking change,
142+
// which is probably undesirable.
143+
//
144+
// Also note that we don't check callee's `track_caller`-ness at all, mostly for the
145+
// reasons above, but also because we can always tailcall the shim we'd generate for
146+
// coercing the function to an `fn()` pointer. (although in that case the tailcall is
147+
// basically useless -- the shim calls the actual function, so tailcalling the shim is
148+
// equivalent to calling the function)
135149
let caller_needs_location = self.needs_location(self.caller_ty);
136-
let callee_needs_location = self.needs_location(ty);
137150

138-
if caller_needs_location != callee_needs_location {
139-
self.report_track_caller_mismatch(expr.span, caller_needs_location);
151+
if caller_needs_location {
152+
self.report_track_caller_caller(expr.span);
140153
}
141154
}
142155

@@ -150,7 +163,9 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
150163
}
151164

152165
/// Returns true if function of type `ty` needs location argument
153-
/// (i.e. if a function is marked as `#[track_caller]`)
166+
/// (i.e. if a function is marked as `#[track_caller]`).
167+
///
168+
/// Panics if the function's instance can't be immediately resolved.
154169
fn needs_location(&self, ty: Ty<'tcx>) -> bool {
155170
if let &ty::FnDef(did, substs) = ty.kind() {
156171
let instance =
@@ -293,25 +308,15 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
293308
self.found_errors = Err(err);
294309
}
295310

296-
fn report_track_caller_mismatch(&mut self, sp: Span, caller_needs_location: bool) {
297-
let err = match caller_needs_location {
298-
true => self
299-
.tcx
300-
.dcx()
301-
.struct_span_err(
302-
sp,
303-
"a function marked with `#[track_caller]` cannot tail-call one that is not",
304-
)
305-
.emit(),
306-
false => self
307-
.tcx
308-
.dcx()
309-
.struct_span_err(
310-
sp,
311-
"a function mot marked with `#[track_caller]` cannot tail-call one that is",
312-
)
313-
.emit(),
314-
};
311+
fn report_track_caller_caller(&mut self, sp: Span) {
312+
let err = self
313+
.tcx
314+
.dcx()
315+
.struct_span_err(
316+
sp,
317+
"a function marked with `#[track_caller]` cannot perform a tail-call",
318+
)
319+
.emit();
315320

316321
self.found_errors = Err(err);
317322
}

tests/crashes/134336.rs

-11
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// regression test for <https://github.com/rust-lang/rust/issues/134336>
2+
// this previously caused an ICE, because we would compare `#[track_caller]` of
3+
// the callee and the caller (in tailcalls specifically), leading to a problem
4+
// since `T::f`'s instance can't be resolved (we do not know if the function is
5+
// or isn't marked with `#[track_caller]`!)
6+
//
7+
//@ check-pass
8+
#![expect(incomplete_features)]
9+
#![feature(explicit_tail_calls)]
10+
11+
trait Tr {
12+
fn f();
13+
}
14+
15+
fn g<T: Tr>() {
16+
become T::f();
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ check-pass
2+
// FIXME(explicit_tail_calls): make this run-pass, once tail calls are properly implemented
3+
#![expect(incomplete_features)]
4+
#![feature(explicit_tail_calls)]
5+
6+
fn a(x: u32) -> u32 {
7+
become b(x);
8+
}
9+
10+
#[track_caller]
11+
fn b(x: u32) -> u32 { x + 42 }
12+
13+
fn main() {
14+
assert_eq!(a(12), 54);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![expect(incomplete_features)]
2+
#![feature(explicit_tail_calls)]
3+
4+
#[track_caller]
5+
fn a() {
6+
become b(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call
7+
}
8+
9+
fn b() {}
10+
11+
#[track_caller]
12+
fn c() {
13+
become a(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: a function marked with `#[track_caller]` cannot perform a tail-call
2+
--> $DIR/caller_is_track_caller.rs:6:5
3+
|
4+
LL | become b();
5+
| ^^^^^^^^^^
6+
7+
error: a function marked with `#[track_caller]` cannot perform a tail-call
8+
--> $DIR/caller_is_track_caller.rs:13:5
9+
|
10+
LL | become a();
11+
| ^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)