From 522442a3710b48de17495700d7d57f7b095a7d57 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 21 Jun 2025 17:18:09 -0700 Subject: [PATCH 1/7] Unwrap track_caller --- src/attributes/codegen.md | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index d472c4db07..f88dfb7066 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -598,26 +598,18 @@ r[attributes.codegen.track_caller] ## The `track_caller` attribute r[attributes.codegen.track_caller.allowed-positions] -The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] -with the exception of the entry point `fn main`. +The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] with the exception of the entry point `fn main`. r[attributes.codegen.track_caller.traits] -When applied to functions and methods in trait declarations, the attribute applies to all implementations. If the trait provides a -default implementation with the attribute, then the attribute also applies to override implementations. +When applied to functions and methods in trait declarations, the attribute applies to all implementations. If the trait provides a default implementation with the attribute, then the attribute also applies to override implementations. r[attributes.codegen.track_caller.extern] -When applied to a function in an `extern` block the attribute must also be applied to any linked -implementations, otherwise undefined behavior results. When applied to a function which is made -available to an `extern` block, the declaration in the `extern` block must also have the attribute, -otherwise undefined behavior results. +When applied to a function in an `extern` block the attribute must also be applied to any linked implementations, otherwise undefined behavior results. When applied to a function which is made available to an `extern` block, the declaration in the `extern` block must also have the attribute, otherwise undefined behavior results. r[attributes.codegen.track_caller.behavior] ### Behavior -Applying the attribute to a function `f` allows code within `f` to get a hint of the [`Location`] of -the "topmost" tracked call that led to `f`'s invocation. At the point of observation, an -implementation behaves as if it walks up the stack from `f`'s frame to find the nearest frame of an -*unattributed* function `outer`, and it returns the [`Location`] of the tracked call in `outer`. +Applying the attribute to a function `f` allows code within `f` to get a hint of the [`Location`] of the "topmost" tracked call that led to `f`'s invocation. At the point of observation, an implementation behaves as if it walks up the stack from `f`'s frame to find the nearest frame of an *unattributed* function `outer`, and it returns the [`Location`] of the tracked call in `outer`. ```rust #[track_caller] @@ -646,8 +638,7 @@ fn calls_f() { } ``` -When `f` is called by another attributed function `g` which is in turn called by `calls_g`, code in -both `f` and `g` observes `g`'s callsite within `calls_g`: +When `f` is called by another attributed function `g` which is in turn called by `calls_g`, code in both `f` and `g` observes `g`'s callsite within `calls_g`: ```rust # #[track_caller] @@ -665,8 +656,7 @@ fn calls_g() { } ``` -When `g` is called by another attributed function `h` which is in turn called by `calls_h`, all code -in `f`, `g`, and `h` observes `h`'s callsite within `calls_h`: +When `g` is called by another attributed function `h` which is in turn called by `calls_h`, all code in `f`, `g`, and `h` observes `h`'s callsite within `calls_h`: ```rust # #[track_caller] @@ -698,10 +688,7 @@ r[attributes.codegen.track_caller.hint] This information is a hint and implementations are not required to preserve it. r[attributes.codegen.track_caller.decay] -In particular, coercing a function with `#[track_caller]` to a function pointer creates a shim which -appears to observers to have been called at the attributed function's definition site, losing actual -caller information across virtual calls. A common example of this coercion is the creation of a -trait object whose methods are attributed. +In particular, coercing a function with `#[track_caller]` to a function pointer creates a shim which appears to observers to have been called at the attributed function's definition site, losing actual caller information across virtual calls. A common example of this coercion is the creation of a trait object whose methods are attributed. > [!NOTE] > The aforementioned shim for function pointers is necessary because `rustc` implements `track_caller` in a codegen context by appending an implicit parameter to the function ABI, but this would be unsound for an indirect call because the parameter is not a part of the function's type and a given function pointer type may or may not refer to a function with the attribute. The creation of a shim hides the implicit parameter from callers of the function pointer, preserving soundness. From edfe733c45621b3cd8deb0e6d6ff37c6816ed031 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 21 Jun 2025 17:37:36 -0700 Subject: [PATCH 2/7] Add attributes.codegen.track_caller.intro --- src/attributes/codegen.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index f88dfb7066..c60fc6667a 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -597,6 +597,9 @@ in the standard library for runtime feature detection on these platforms. r[attributes.codegen.track_caller] ## The `track_caller` attribute +r[attributes.codegen.track_caller.intro] +The *`track_caller` [attribute][attributes]* is used on functions to indicate that the caller should be tracked for the purpose of using [`Location`] to determine the caller. + r[attributes.codegen.track_caller.allowed-positions] The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] with the exception of the entry point `fn main`. From 635a527659375579dd752db42011f9319fbde6a9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 21 Jun 2025 17:37:54 -0700 Subject: [PATCH 3/7] Move track_caller example to an example block --- src/attributes/codegen.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index c60fc6667a..a30ce96e82 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -600,6 +600,14 @@ r[attributes.codegen.track_caller] r[attributes.codegen.track_caller.intro] The *`track_caller` [attribute][attributes]* is used on functions to indicate that the caller should be tracked for the purpose of using [`Location`] to determine the caller. +> [!EXAMPLE] +> ```rust +> #[track_caller] +> fn f() { +> println!("{}", std::panic::Location::caller()); +> } +> ``` + r[attributes.codegen.track_caller.allowed-positions] The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] with the exception of the entry point `fn main`. @@ -614,13 +622,6 @@ r[attributes.codegen.track_caller.behavior] Applying the attribute to a function `f` allows code within `f` to get a hint of the [`Location`] of the "topmost" tracked call that led to `f`'s invocation. At the point of observation, an implementation behaves as if it walks up the stack from `f`'s frame to find the nearest frame of an *unattributed* function `outer`, and it returns the [`Location`] of the tracked call in `outer`. -```rust -#[track_caller] -fn f() { - println!("{}", std::panic::Location::caller()); -} -``` - > [!NOTE] > `core` provides [`core::panic::Location::caller`] for observing caller locations. It wraps the [`core::intrinsics::caller_location`] intrinsic implemented by `rustc`. From ef018a2e0462d9a383ef098b97299e6b51b263e6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 21 Jun 2025 17:39:11 -0700 Subject: [PATCH 4/7] Move track_caller example to an example block --- src/attributes/codegen.md | 111 +++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index a30ce96e82..957ca7b894 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -628,62 +628,61 @@ Applying the attribute to a function `f` allows code within `f` to get a hint of > [!NOTE] > Because the resulting `Location` is a hint, an implementation may halt its walk up the stack early. See [Limitations](#limitations) for important caveats. -#### Examples - -When `f` is called directly by `calls_f`, code in `f` observes its callsite within `calls_f`: - -```rust -# #[track_caller] -# fn f() { -# println!("{}", std::panic::Location::caller()); -# } -fn calls_f() { - f(); // <-- f() prints this location -} -``` - -When `f` is called by another attributed function `g` which is in turn called by `calls_g`, code in both `f` and `g` observes `g`'s callsite within `calls_g`: - -```rust -# #[track_caller] -# fn f() { -# println!("{}", std::panic::Location::caller()); -# } -#[track_caller] -fn g() { - println!("{}", std::panic::Location::caller()); - f(); -} - -fn calls_g() { - g(); // <-- g() prints this location twice, once itself and once from f() -} -``` - -When `g` is called by another attributed function `h` which is in turn called by `calls_h`, all code in `f`, `g`, and `h` observes `h`'s callsite within `calls_h`: - -```rust -# #[track_caller] -# fn f() { -# println!("{}", std::panic::Location::caller()); -# } -# #[track_caller] -# fn g() { -# println!("{}", std::panic::Location::caller()); -# f(); -# } -#[track_caller] -fn h() { - println!("{}", std::panic::Location::caller()); - g(); -} - -fn calls_h() { - h(); // <-- prints this location three times, once itself, once from g(), once from f() -} -``` - -And so on. +> [!EXAMPLE] +> When `f` is called directly by `calls_f`, code in `f` observes its callsite within `calls_f`: +> +> ```rust +> # #[track_caller] +> # fn f() { +> # println!("{}", std::panic::Location::caller()); +> # } +> fn calls_f() { +> f(); // <-- f() prints this location +> } +> ``` +> +> When `f` is called by another attributed function `g` which is in turn called by `calls_g`, code in both `f` and `g` observes `g`'s callsite within `calls_g`: +> +> ```rust +> # #[track_caller] +> # fn f() { +> # println!("{}", std::panic::Location::caller()); +> # } +> #[track_caller] +> fn g() { +> println!("{}", std::panic::Location::caller()); +> f(); +> } +> +> fn calls_g() { +> g(); // <-- g() prints this location twice, once itself and once from f() +> } +> ``` +> +> When `g` is called by another attributed function `h` which is in turn called by `calls_h`, all code in `f`, `g`, and `h` observes `h`'s callsite within `calls_h`: +> +> ```rust +> # #[track_caller] +> # fn f() { +> # println!("{}", std::panic::Location::caller()); +> # } +> # #[track_caller] +> # fn g() { +> # println!("{}", std::panic::Location::caller()); +> # f(); +> # } +> #[track_caller] +> fn h() { +> println!("{}", std::panic::Location::caller()); +> g(); +> } +> +> fn calls_h() { +> h(); // <-- prints this location three times, once itself, once from g(), once from f() +> } +> ``` +> +> And so on. r[attributes.codegen.track_caller.limits] ### Limitations From ff631ae95f93ad9b302bea2f19e01b90dd488f84 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 21 Jun 2025 17:39:46 -0700 Subject: [PATCH 5/7] Rename "limitations" header to make it more specific --- src/attributes/codegen.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 957ca7b894..22458acbbd 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -626,7 +626,7 @@ Applying the attribute to a function `f` allows code within `f` to get a hint of > `core` provides [`core::panic::Location::caller`] for observing caller locations. It wraps the [`core::intrinsics::caller_location`] intrinsic implemented by `rustc`. > [!NOTE] -> Because the resulting `Location` is a hint, an implementation may halt its walk up the stack early. See [Limitations](#limitations) for important caveats. +> Because the resulting `Location` is a hint, an implementation may halt its walk up the stack early. See [Limitations](#track_caller-limitations) for important caveats. > [!EXAMPLE] > When `f` is called directly by `calls_f`, code in `f` observes its callsite within `calls_f`: @@ -685,7 +685,7 @@ Applying the attribute to a function `f` allows code within `f` to get a hint of > And so on. r[attributes.codegen.track_caller.limits] -### Limitations +### `track_caller` limitations r[attributes.codegen.track_caller.hint] This information is a hint and implementations are not required to preserve it. From b134234f2d8b13958c1d92cbc7a4773fea622d91 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 21 Jun 2025 17:40:11 -0700 Subject: [PATCH 6/7] Update track_caller to use the attribute template --- src/attributes/codegen.md | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index 22458acbbd..b9d9102443 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -608,19 +608,37 @@ The *`track_caller` [attribute][attributes]* is used on functions to indicate th > } > ``` +r[attributes.codegen.track_caller.syntax] +The `track_caller` attribute uses the [MetaWord] syntax and thus does not take any inputs. + r[attributes.codegen.track_caller.allowed-positions] -The `track_caller` attribute may be applied to any function with [`"Rust"` ABI][rust-abi] with the exception of the entry point `fn main`. +The `track_caller` attribute may only be applied to: + +- [Free functions][items.fn] +- [Inherent associated functions][items.associated.fn] +- [Trait impl functions][items.impl.trait] +- [Trait definition functions][items.traits] +- [External block functions][items.extern.fn] +- [Closures][expr.closure] + +All functions must have the [`"Rust"` ABI][rust-abi]. + +It may not be applied to the [the `main` function][crate.main]. + +r[attributes.codegen.track_caller.duplicates] +Duplicate instances of the `track_caller` attribute are ignored. + +> [!NOTE] +> `rustc` warns on on duplicate `track_caller` attributes. r[attributes.codegen.track_caller.traits] -When applied to functions and methods in trait declarations, the attribute applies to all implementations. If the trait provides a default implementation with the attribute, then the attribute also applies to override implementations. +When applied to functions and methods in trait declarations, the `track_caller` attribute applies to all implementations. If the trait provides a default implementation with the attribute, then the attribute also applies to override implementations. r[attributes.codegen.track_caller.extern] -When applied to a function in an `extern` block the attribute must also be applied to any linked implementations, otherwise undefined behavior results. When applied to a function which is made available to an `extern` block, the declaration in the `extern` block must also have the attribute, otherwise undefined behavior results. +When applied to a function in an `extern` block, the `track_caller` attribute must also be applied to any linked implementations, otherwise undefined behavior results. When applied to a function which is made available to an `extern` block, the declaration in the `extern` block must also have the attribute, otherwise undefined behavior results. r[attributes.codegen.track_caller.behavior] -### Behavior - -Applying the attribute to a function `f` allows code within `f` to get a hint of the [`Location`] of the "topmost" tracked call that led to `f`'s invocation. At the point of observation, an implementation behaves as if it walks up the stack from `f`'s frame to find the nearest frame of an *unattributed* function `outer`, and it returns the [`Location`] of the tracked call in `outer`. +Applying the `track_caller` attribute to a function `f` allows code within `f` to get a hint of the [`Location`] of the *topmost* tracked call that led to `f`'s invocation. At the point of observation, an implementation behaves as if it walks up the stack from `f`'s frame to find the nearest frame of an *unattributed* function `outer`, and it returns the [`Location`] of the tracked call in `outer`. > [!NOTE] > `core` provides [`core::panic::Location::caller`] for observing caller locations. It wraps the [`core::intrinsics::caller_location`] intrinsic implemented by `rustc`. From 9bfee1f165c1619874244bef3a25d307e3043f84 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 7 Oct 2025 14:03:17 -0700 Subject: [PATCH 7/7] Update track_caller for updated attribute template --- src/attributes/codegen.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index b9d9102443..56c8d5f581 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -594,6 +594,7 @@ in the standard library for runtime feature detection on these platforms. > [!NOTE] > `rustc` has a default set of features enabled for each target and CPU. The CPU may be chosen with the [`-C target-cpu`] flag. Individual features may be enabled or disabled for an entire crate with the [`-C target-feature`] flag. + r[attributes.codegen.track_caller] ## The `track_caller` attribute @@ -609,7 +610,7 @@ The *`track_caller` [attribute][attributes]* is used on functions to indicate th > ``` r[attributes.codegen.track_caller.syntax] -The `track_caller` attribute uses the [MetaWord] syntax and thus does not take any inputs. +The `track_caller` attribute uses the [MetaWord] syntax. r[attributes.codegen.track_caller.allowed-positions] The `track_caller` attribute may only be applied to: @@ -626,10 +627,10 @@ All functions must have the [`"Rust"` ABI][rust-abi]. It may not be applied to the [the `main` function][crate.main]. r[attributes.codegen.track_caller.duplicates] -Duplicate instances of the `track_caller` attribute are ignored. +Only the first use of `track_caller` on an item has effect. > [!NOTE] -> `rustc` warns on on duplicate `track_caller` attributes. +> `rustc` lints against any use following the first. r[attributes.codegen.track_caller.traits] When applied to functions and methods in trait declarations, the `track_caller` attribute applies to all implementations. If the trait provides a default implementation with the attribute, then the attribute also applies to override implementations.