about summary refs log tree commit diff
path: root/compiler/rustc_lint_defs
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-08-15 16:16:31 +1000
committerGitHub <noreply@github.com>2025-08-15 16:16:31 +1000
commit44eb7a167c9df395c803bf113a933f668b4c278a (patch)
tree0b352a5e4f981570afdb0135b40f873df7a56441 /compiler/rustc_lint_defs
parent603b61df5768c95c994a4cde42898edf394c5f6f (diff)
parentfa18b3ebe29154440f6e8d9ad83021802b3aaa29 (diff)
downloadrust-44eb7a167c9df395c803bf113a933f668b4c278a.tar.gz
rust-44eb7a167c9df395c803bf113a933f668b4c278a.zip
Rollup merge of #144865 - WaffleLapkin:track-tail, r=lqd
Fix tail calls to `#[track_caller]` functions

We want `#[track_caller]` to be semver independent, i.e. it should not be a breaking change to add or remove it. Since it changes ABI of a function (adding an additional argument) we have to be careful to preserve this property when adding tail calls.

The only way to achieve this that I can see is:
- we forbid tail calls in functions which are marked with `#[track_caller]` (already implemented)
- tail-calling a `#[track_caller]` marked function downgrades the tail-call to a normal call (or equivalently tail-calls the shim made by fn def to fn ptr cast) (this pr)

Ideally the downgrade would be performed by a MIR pass, but that requires post mono MIR opts (cc ```@saethlin,``` rust-lang/rust#131650). For now I've changed code in cg_ssa to accomodate this behaviour (+ added a hack to mono collector so that the shim is actually generated)

Additionally I added a lint, although I don't think it's strictly necessary.

Alternative to rust-lang/rust#144762 (and thus closes rust-lang/rust#144762)
Fixes https://github.com/rust-lang/rust/issues/144755
Diffstat (limited to 'compiler/rustc_lint_defs')
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index bee80335f74..a0083a7df3d 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -5105,3 +5105,36 @@ declare_lint! {
         report_in_deps: true,
     };
 }
+
+declare_lint! {
+    /// The `tail_call_track_caller` lint detects usage of `become` attempting to tail call
+    /// a function marked with `#[track_caller]`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(explicit_tail_calls)]
+    /// #![expect(incomplete_features)]
+    ///
+    /// #[track_caller]
+    /// fn f() {}
+    ///
+    /// fn g() {
+    ///     become f();
+    /// }
+    ///
+    /// g();
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Due to implementation details of tail calls and `#[track_caller]` attribute, calls to
+    /// functions marked with `#[track_caller]` cannot become tail calls. As such using `become`
+    /// is no different than a normal call (except for changes in drop order).
+    pub TAIL_CALL_TRACK_CALLER,
+    Warn,
+    "detects tail calls of functions marked with `#[track_caller]`",
+    @feature_gate = explicit_tail_calls;
+}