This attributes ensures the function call at function return is tail call optimized.
So the stack size is O(1) instead of O(n),
and there are many performance improvement opportunities with this feature
I do not find this in Rustc unstable book
How to implement:
LLVM IR "Call" instruction already support "musttail"
Add a new attribute "musttail", which can be applied to function call (or function declaration).
The HIR and MIR needs to verify this and keep track of this attribute
It's a bit frustrating that this has been postponed multiple times, the last one in 2018. We're in 2022, can this discussion finally be restarted?
I would like to at least have the compiler provide the tools to iterate it on the crates ecosystem, even if it works only on nightly; or provide a nightly-only attribute, or something, and see where it goes (multiple people wrote compiler patches for tail calls to work, but they are stale now; it would be much better to have a #[tail_call] nightly-only macro)
To have a chance to stabilize, it would need a plan to stabilize on all supported architectures. IIRC last it came up there was no native tail call support on WASM, for example. So, in general, it might not be possible to enable arbitrary tail calls.
The question, then, is what kind of more-restricted construct could meet your needs? Is intra-crate calls enough? rustc could, hypothetically, always rewrite such calls into a loop itself.
Or maybe it doesn't need even that much. The most feasible version might be an inside-a-function custom control flow construct, like described in [Pre-RFC] Safe goto with value - #9 by scottmcm. Then, instead of become dispatch(…) it might be continue 'dispatch, locally in the function so there isn't even tail call optimization needed since it'd just be one big CFG.
The [[musttail]] attribute is introduced in Clang in 2021.
At the time of the initial discussion on 2014, Clang does not have it.
I may propose a RPC when I have time.
I think it's probably the time to have it in Rust.
I do not like the become keywords in the 8 year RFC PR.
Because The tail call requirement should not change the behavior of the Rust program.
Since this is not supported by all architecture,
I think it is more appropriate to introduce it under the target_feature attribute.
The drawback is that this is the first target feature which is shared by multiple targets.
If this target does not support musttail, a compiler error is issued.
This can be done by adding a "musttail" field in the target spec json,
produced by rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json
Only targets supported by Clang will be supported in Rust. Compile error otherwise.
The musttail attr can only be applied to a return.
The musttail attr can only be applied to a call expression.
The returned function cannot be a lambda function (Not supported in Clang either)
This can be relaxed to support stateless lambda function.
No destructor (Types explicitly implement the drop trait) call is allowed on tail call return.
They must be out of lifetime, or be explicitly manually dropped earlier.
Two functions must have the same ABI
The call arguments must not contain any reference to the local variables of the parent function.
Can function pointer be supported (This is supported by clang)?
Should the function under return have exactly same return value as the parent function.
Should Type coercions be allowed?
Community feedback suggested that an attribute on a regular-syntax return statement might be
preferable for linguistic reasons. However, this is impossible: a standard attribute can be ignored
without changing the meaning of a correct program, while changing a return goto statement to
a return statement (or vice-versa) significantly changes the meaning of both the statement itself,
and the calling function’s scope in terms of object lifetimes
There is an active proposal to add a return_call instruction to WASM. It's already implemented by V8/Chrome but feature gated. The only blocker seems to be that no second engine implements the proposal yet.
Why "should"? Notably that's not what clang's support does.
But also this is why above I was talking about a more limited construct, because if the frontend has to do it, that can only ever work in restricted scenarios (at least if separate compilation is going to be a thing).
So the question, then, is in what scenarios people actually need guaranteed tail calls, rather than just as an optimization. Some of them are easy, like tail recursion the frontend could certainly do. But do cross-crate calls ever need guaranteed tail calls, for example?
Precisely because it is unreasonable to expect that every target and every backend has proper support for tail calls. It's also looks complex enough that it's more reasonable to implement once in the frontend, rather than in every possible backend.
It's a damn important optimization, if you happen to rely on it. That's a sufficient reason for me. But I admit, I didn't think about cross-crate tail calls. The most important optimization for me is tail recursion, at most mutual tail recursion between several functions in a module.