about summary refs log tree commit diff
path: root/library/std/src/keyword_docs.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-09-13 23:02:12 +0000
committerbors <bors@rust-lang.org>2025-09-13 23:02:12 +0000
commita015919e54c60b1b2bec7a98dec478cfc4a48f4e (patch)
tree8a1fc4a0c27ec87edc0d0449bb4fa3dab130bab6 /library/std/src/keyword_docs.rs
parent02c7b1a7ac1d739663878030510508372e46f254 (diff)
parentda1c27df16075d9ebb28a94cf9b400e89c476233 (diff)
downloadrust-a015919e54c60b1b2bec7a98dec478cfc4a48f4e.tar.gz
rust-a015919e54c60b1b2bec7a98dec478cfc4a48f4e.zip
Auto merge of #146526 - jhpratt:rollup-afb1dgo, r=jhpratt
Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#113095 (Document `become` keyword)
 - rust-lang/rust#146159 (Some hygiene doc improvements)
 - rust-lang/rust#146171 (tidy: check that error messages don't start with a capitalized letter)
 - rust-lang/rust#146419 (Update the arm-* and aarch64-* platform docs.)
 - rust-lang/rust#146473 (Revert "Constify SystemTime methods")
 - rust-lang/rust#146506 (Fix small typo in check-cfg.md)
 - rust-lang/rust#146517 (fix Condvar::wait_timeout docs)
 - rust-lang/rust#146521 (document `core::ffi::VaArgSafe`)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'library/std/src/keyword_docs.rs')
-rw-r--r--library/std/src/keyword_docs.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 1c55824ab90..7ff4af8ede8 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1257,6 +1257,108 @@ mod ref_keyword {}
 /// [`async`]: ../std/keyword.async.html
 mod return_keyword {}
 
+#[doc(keyword = "become")]
+//
+/// Perform a tail-call of a function.
+///
+/// <div class="warning">
+///
+/// `feature(explicit_tail_calls)` is currently incomplete and may not work properly.
+/// </div>
+///
+/// When tail calling a function, instead of its stack frame being added to the
+/// stack, the stack frame of the caller is directly replaced with the callee's.
+/// This means that as long as a loop in a call graph only uses tail calls, the
+/// stack growth will be bounded.
+///
+/// This is useful for writing functional-style code (since it prevents recursion
+/// from exhausting resources) or for code optimization (since a tail call
+/// *might* be cheaper than a normal call, tail calls can be used in a similar
+/// manner to computed goto).
+///
+/// Example of using `become` to implement functional-style `fold`:
+/// ```
+/// #![feature(explicit_tail_calls)]
+/// #![expect(incomplete_features)]
+///
+/// fn fold<T: Copy, S>(slice: &[T], init: S, f: impl Fn(S, T) -> S) -> S {
+///     match slice {
+///         // without `become`, on big inputs this could easily overflow the
+///         // stack. using a tail call guarantees that the stack will not grow unboundedly
+///         [first, rest @ ..] => become fold(rest, f(init, *first), f),
+///         [] => init,
+///     }
+/// }
+/// ```
+///
+/// Compilers can already perform "tail call optimization" -- they can replace normal
+/// calls with tail calls, although there are no guarantees that this will be done.
+/// However, to perform TCO, the call needs to be the last thing that happens
+/// in the functions and be returned from it. This requirement is often broken
+/// by drop code for locals, which is run after computing the return expression:
+///
+/// ```
+/// fn example() {
+///     let string = "meow".to_owned();
+///     println!("{string}");
+///     return help(); // this is *not* the last thing that happens in `example`...
+/// }
+///
+/// // ... because it is desugared to this:
+/// fn example_desugared() {
+///     let string = "meow".to_owned();
+///     println!("{string}");
+///     let tmp = help();
+///     drop(string);
+///     return tmp;
+/// }
+///
+/// fn help() {}
+/// ```
+///
+/// For this reason, `become` also changes the drop order, such that locals are
+/// dropped *before* evaluating the call.
+///
+/// In order to guarantee that the compiler can perform a tail call, `become`
+/// currently has these requirements:
+/// 1. callee and caller must have the same ABI, arguments, and return type
+/// 2. callee and caller must not have varargs
+/// 3. caller must not be marked with `#[track_caller]`
+///    - callee is allowed to be marked with `#[track_caller]` as otherwise
+///      adding `#[track_caller]` would be a breaking change. if callee is
+///      marked with `#[track_caller]` a tail call is not guaranteed.
+/// 4. callee and caller cannot be a closure
+///    (unless it's coerced to a function pointer)
+///
+/// It is possible to tail-call a function pointer:
+/// ```
+/// #![feature(explicit_tail_calls)]
+/// #![expect(incomplete_features)]
+///
+/// #[derive(Copy, Clone)]
+/// enum Inst { Inc, Dec }
+///
+/// fn dispatch(stream: &[Inst], state: u32) -> u32 {
+///     const TABLE: &[fn(&[Inst], u32) -> u32] = &[increment, decrement];
+///     match stream {
+///         [inst, rest @ ..] => become TABLE[*inst as usize](rest, state),
+///         [] => state,
+///     }
+/// }
+///
+/// fn increment(stream: &[Inst], state: u32) -> u32 {
+///     become dispatch(stream, state + 1)
+/// }
+///
+/// fn decrement(stream: &[Inst], state: u32) -> u32 {
+///     become dispatch(stream, state - 1)
+/// }
+///
+/// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc];
+/// assert_eq!(dispatch(program, 0), 2);
+/// ```
+mod become_keyword {}
+
 #[doc(keyword = "self")]
 //
 /// The receiver of a method, or the current module.