On the other hand, I am pretty new to the compiler space myself, and I count early 2000s as a pretty long time ago, though again it is not that far back considering how long other language implementations had tail calls like in ML or variants since 1980-90s.
You won't find anything on ISO/IEC 9899:2024 about tail calls, like it happens on Scheme.
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf
Section 3.5 of R7RS.
1. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3886.pdf
2. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3928.pdf
Is it really surprising in 2026? Today's online writing style is not primarily designed to communicate. It's designed to keep the reader 'engaged' for as long as possible. The reader's time is a resource to be extracted.
I'm absolutely not poking this author individually. It's the writing style of the net.
This leads to fun stack-overflow bugs too in a lot of js code (one solution is to flatten: https://joshua.hu/javascript-infinite-tail-call-recursion-st...)
This proposal would give Rust a specific keyword which says that you intend TCO and so two things happen: 1. The compiler goes to more length to deliver TCO even where it wouldn't "just work" and 2. If it cannot deliver TCO your code doesn't compile, because you asked for TCO.
This has always been an issue regarding TCO support across programming languages.
MSVC didn't add tail-call optimisation until sometime in the 2010s, IIRC.
I distinctly remember sending a tail-recursive C++ program to someone who developed on Windows, and it crashing, in the late mid-to-late 2000s.
It famously doesn’t support a few features of C99.
They don’t really seem to care much about regular C support (non-C++).
https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...
Note,
"If you really need either of the following.....then we recommend that you consider using a different compiler such as Intel or gcc (short-term) and/or pressure your standards committee representatives to have ISO C++ include more of the C standard (longer-term)."
Which is kind of why nowadays clang is part of Visual Studio as well.
However, after Satya got into the whole Microsoft <3 FOSS, this changed a bit,
https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-...
There are a few blogs after that, so at least up to C17 minus the optional parts from C11, the support is there.
It remains to be seen if anything C23 or later will ever come into MSVC, and then again, clang is part of VS installer.
Relatively recent being a quarter of century? Or at least a fifth of a century for indirect calls[1] (GCC 3.4.6 is the earliest I see on Compiler Explorer, released March 2006).
On such an implementation, the feature is available but useless.
Another related footgun is deep recursion of other kinds, for example when recursively traversing down lists. For long lists it's easy to exceed the stack size limit. The common idiom is to recur on list elements, but iterate or map to go along a list.
Presumably one intends to debug the code, when setting (debug 3). Then it'll be helpful to see the stack, no?
> Another related footgun is deep recursion of other kinds, for example when recursively traversing down lists. For long lists it's easy to exceed the stack size limit. The common idiom is to recur on list elements, but iterate or map to go along a list.
Not going to argue with seasoned lispers here, but IMHO recursive code makes most sense when accessing recursive data structures.
This can also be seen as an argument against building parse trees that way. Instead, have a node with an unbounded number of children, the elements of the list.
I personally use the phrase "tail call elimination" when it's a requirement that can be relied on; and "tail call optimisation" when it might be implementation-dependent, context-dependent, limited (e.g. to immediate self-calls), etc.
Secondly however in these languages you often won't naively get TCO because you have at least one local variable which C++ would say has a "non-trivial destructor" or Rust would say "implements Drop". These both mean that naively the "tail call" wasn't actually the last thing to happen, the destructor / Drop::drop happen at the end of the function, after the tail call.
The proposed become keyword tries to core::mem::drop any such variables, if it succeeds now that tail call is last and we can do TCO, if it fails [e.g. because the variables it wants to drop are needed for the tail call] we can diagnose the problem. I believe the Clang attribute doesn't have this behaviour.