@@ -143,6 +143,113 @@ feature detection on the x86 platforms.
143143> may be enabled or disabled for an entire crate with the
144144> [ ` -C target-feature ` ] flag.
145145
146+ ## The ` track_caller ` attribute
147+
148+ The ` track_caller ` attribute may be applied to any function with [ ` "Rust" ` ABI] [ rust-abi ] . When
149+ applied to functions and methods in trait declarations, the attribute applies to all
150+ implementations. If the trait provides a default implementation with the attribute, then the
151+ attribute also applies to override implementations.
152+
153+ When applied to a function in an ` extern ` block the attribute must also be applied to any linked
154+ implementations, otherwise undefined behavior results. When applied to a function which is made
155+ available to an ` extern ` block, the declaration in the ` extern ` block must also have the attribute,
156+ otherwise undefined behavior results.
157+
158+ ### Behavior
159+
160+ Applying the attribute to a function ` f ` allows code within ` f ` to get a hint of the [ ` Location ` ] of
161+ the "topmost" tracked call that led to ` f ` 's invocation. At the point of observation, an
162+ implementation behaves as if it walks up the stack from ` f ` 's frame to find the nearest frame of an
163+ * unattributed* function ` outer ` , and it returns the [ ` Location ` ] of the tracked call in ` outer ` .
164+
165+ ``` rust
166+ #[track_caller]
167+ fn f () {
168+ println! (" {}" , std :: panic :: Location :: caller ());
169+ }
170+ ```
171+
172+ > Note: ` core ` provides [ ` core::panic::Location::caller ` ] for observing caller locations. It wraps
173+ > the [ ` core::intrinsics::caller_location ` ] intrinsic implemented by ` rustc ` .
174+
175+ > Note: because the resulting ` Location ` is a hint, an implementation may halt its walk up the stack
176+ > early. See [ Limitations] ( #limitations ) for important caveats.
177+
178+ #### Examples
179+
180+ When ` f ` is called directly by ` calls_f ` , code in ` f ` observes its callsite within ` calls_f ` :
181+
182+ ``` rust
183+ # #[track_caller]
184+ # fn f () {
185+ # println! (" {}" , std :: panic :: Location :: caller ());
186+ # }
187+ fn calls_f () {
188+ f (); // <-- f() prints this location
189+ }
190+ ```
191+
192+ When ` f ` is called by another attributed function ` g ` which is in turn called by ` calls_g ` , code in
193+ both ` f ` and ` g ` observes ` g ` 's callsite within ` calls_g ` :
194+
195+ ``` rust
196+ # #[track_caller]
197+ # fn f () {
198+ # println! (" {}" , std :: panic :: Location :: caller ());
199+ # }
200+ #[track_caller]
201+ fn g () {
202+ println! (" {}" , std :: panic :: Location :: caller ());
203+ f ();
204+ }
205+
206+ fn calls_g () {
207+ g (); // <-- g() prints this location twice, once itself and once from f()
208+ }
209+ ```
210+
211+ When ` g ` is called by another attributed function ` h ` which is in turn called by ` calls_h ` , all code
212+ in ` f ` , ` g ` , and ` h ` observes ` h ` 's callsite within ` calls_h ` :
213+
214+ ``` rust
215+ # #[track_caller]
216+ # fn f () {
217+ # println! (" {}" , std :: panic :: Location :: caller ());
218+ # }
219+ # #[track_caller]
220+ # fn g () {
221+ # println! (" {}" , std :: panic :: Location :: caller ());
222+ # f ();
223+ # }
224+ #[track_caller]
225+ fn h () {
226+ println! (" {}" , std :: panic :: Location :: caller ());
227+ g ();
228+ }
229+
230+ fn calls_h () {
231+ h (); // <-- prints this location three times, once itself, once from g(), once from f()
232+ }
233+ ```
234+
235+ And so on.
236+
237+ ### Limitations
238+
239+ This information is a hint and implementations are not required to preserve it.
240+
241+ In particular, coercing a function with ` #[track_caller] ` to a function pointer creates a shim which
242+ appears to observers to have been called at the attributed function's definition site, losing actual
243+ caller information across virtual calls. A common example of this coercion is the creation of a
244+ trait object whose methods are attributed.
245+
246+ > Note: The aforementioned shim for function pointers is necessary because ` rustc ` implements
247+ > ` track_caller ` in a codegen context by appending an implicit parameter to the function ABI, but
248+ > this would be unsound for an indirect call because the parameter is not a part of the function's
249+ > type and a given function pointer type may or may not refer to a function with the attribute. The
250+ > creation of a shim hides the implicit parameter from callers of the function pointer, preserving
251+ > soundness.
252+
146253[ _MetaListNameValueStr_ ] : ../attributes.md#meta-item-attribute-syntax
147254[ `-C target-cpu` ] : ../../rustc/codegen-options/index.html#target-cpu
148255[ `-C target-feature` ] : ../../rustc/codegen-options/index.html#target-feature
@@ -155,3 +262,7 @@ feature detection on the x86 platforms.
155262[ trait ] : ../items/traits.md
156263[ undefined behavior ] : ../behavior-considered-undefined.md
157264[ unsafe function ] : ../unsafe-functions.md
265+ [ rust-abi ] : ../items/external-blocks.md#abi
266+ [ `core::intrinsics::caller_location` ] : ../../core/intrinsics/fn.caller_location.html
267+ [ `core::panic::Location::caller` ] : ../../core/panic/struct.Location.html#method.caller
268+ [ `Location` ] : ../../core/panic/struct.Location.html
0 commit comments