3
3
<!-- toc -->
4
4
5
5
Approved in [ RFC 2091] , this feature enables the accurate reporting of caller location during panics
6
- initiated from functions like ` Option::unwrap ` , ` Result::expect ` , and ` Index::index ` . This feature
7
- adds the [ ` #[track_caller] ` ] [ attr-reference ] attribute for functions, the
8
- [ ` caller_location ` ] [ intrinsic ] intrinsic, and the stabilization-friendly
6
+ initiated from functions like ` Option::unwrap ` , ` Result::expect ` , and ` Index::index ` . This feature
7
+ adds the [ ` #[track_caller] ` ] [ attr-reference ] attribute for functions, the
8
+ [ ` caller_location ` ] [ intrinsic ] intrinsic, and the stabilization-friendly
9
9
[ ` core::panic::Location::caller ` ] [ wrapper ] wrapper.
10
10
11
11
## Motivating Example
@@ -30,25 +30,25 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
30
30
As of 1.42, we get a much more helpful message:
31
31
32
32
```
33
- $ rustc +1.42.0 example.rs; example.exe
33
+ $ rustc +1.42.0 example.rs; example.exe
34
34
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', example.rs:3:5
35
35
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
36
36
```
37
37
38
38
These error messages are achieved through a combination of changes to ` panic! ` internals to make use
39
- of ` core::panic::Location::caller ` and a number of ` #[track_caller] ` annotations in the standard
39
+ of ` core::panic::Location::caller ` and a number of ` #[track_caller] ` annotations in the standard
40
40
library which propagate caller information.
41
41
42
42
## Reading Caller Location
43
43
44
44
Previously, ` panic! ` made use of the ` file!() ` , ` line!() ` , and ` column!() ` macros to construct a
45
45
[ ` Location ` ] pointing to where the panic occurred. These macros couldn't be given an overridden
46
- location, so functions which intentionally invoked ` panic! ` couldn't provide their own location,
46
+ location, so functions which intentionally invoked ` panic! ` couldn't provide their own location,
47
47
hiding the actual source of error.
48
48
49
- Internally, ` panic!() ` now calls [ ` core::panic::Location::caller() ` ] [ wrapper ] to find out where it
50
- was expanded. This function is itself annotated with ` #[track_caller] ` and wraps the
51
- [ ` caller_location ` ] [ intrinsic ] compiler intrinsic implemented by rustc. This intrinsic is easiest
49
+ Internally, ` panic!() ` now calls [ ` core::panic::Location::caller() ` ] [ wrapper ] to find out where it
50
+ was expanded. This function is itself annotated with ` #[track_caller] ` and wraps the
51
+ [ ` caller_location ` ] [ intrinsic ] compiler intrinsic implemented by rustc. This intrinsic is easiest
52
52
explained in terms of how it works in a ` const ` context.
53
53
54
54
## Caller Location in ` const `
@@ -58,20 +58,20 @@ to find the right location and allocating a const value to return.
58
58
59
59
### Finding the right ` Location `
60
60
61
- In a const context we "walk up the stack" from where the intrinsic is invoked, stopping when we
61
+ In a const context we "walk up the stack" from where the intrinsic is invoked, stopping when we
62
62
reach the first function call in the stack which does * not* have the attribute. This walk is in
63
63
[ ` InterpCx::find_closest_untracked_caller_location() ` ] [ const-find-closest ] .
64
64
65
- Starting at the bottom, we iterate up over stack [ ` Frame ` ] [ const-frame ] s in the
65
+ Starting at the bottom, we iterate up over stack [ ` Frame ` ] [ const-frame ] s in the
66
66
[ ` InterpCx::stack ` ] [ const-stack ] , calling
67
- [ ` InstanceDef::requires_caller_location ` ] [ requires-location ] on the
67
+ [ ` InstanceDef::requires_caller_location ` ] [ requires-location ] on the
68
68
[ ` Instance ` s from each ` Frame ` ] [ frame-instance ] . We stop once we find one that returns ` false ` and
69
69
return the span of the * previous* frame which was the "topmost" tracked function.
70
70
71
71
### Allocating a static ` Location `
72
72
73
- Once we have a ` Span ` , we need to allocate static memory for the ` Location ` , which is performed by
74
- the [ ` TyCtxt::const_caller_location() ` ] [ const-location-query ] query. Internally this calls
73
+ Once we have a ` Span ` , we need to allocate static memory for the ` Location ` , which is performed by
74
+ the [ ` TyCtxt::const_caller_location() ` ] [ const-location-query ] query. Internally this calls
75
75
[ ` InterpCx::alloc_caller_location() ` ] [ alloc-location ] and results in a unique
76
76
[ memory kind] [ location-memory-kind ] (` MemoryKind::CallerLocation ` ). The SSA codegen backend is able
77
77
to emit code for these same values, and we use this code there as well.
@@ -80,14 +80,14 @@ Once our `Location` has been allocated in static memory, our intrinsic returns a
80
80
81
81
## Generating code for ` #[track_caller] ` callees
82
82
83
- To generate efficient code for a tracked function and its callers, we need to provide the same
83
+ To generate efficient code for a tracked function and its callers, we need to provide the same
84
84
behavior from the intrinsic's point of view without having a stack to walk up at runtime. We invert
85
85
the approach: as we grow the stack down we pass an additional argument to calls of tracked functions
86
86
rather than walking up the stack when the intrinsic is called. That additional argument can be
87
87
returned wherever the caller location is queried.
88
88
89
89
The argument we append is of type ` &'static core::panic::Location<'static> ` . A reference was chosen
90
- to avoid unnecessary copying because a pointer is a third the size of
90
+ to avoid unnecessary copying because a pointer is a third the size of
91
91
` std::mem::size_of::<core::panic::Location>() == 24 ` at time of writing.
92
92
93
93
When generating a call to a function which is tracked, we pass the location argument the value of
@@ -153,12 +153,12 @@ probably the best we can do without modifying fully-stabilized type signatures.
153
153
154
154
> * Note:* We always emit a [ ` ReifyShim ` ] when taking a pointer to a tracked function. While the
155
155
> constraint here is imposed by codegen contexts, we don't know during MIR construction of the shim
156
- > whether we'll be called in a const context (safe to ignore shim) or in a codegen context (unsafe
156
+ > whether we'll be called in a const context (safe to ignore shim) or in a codegen context (unsafe
157
157
> to ignore shim). Even if we did know, the results from const and codegen contexts must agree.
158
158
159
159
## The Attribute
160
160
161
- The ` #[track_caller] ` attribute is checked alongside other codegen attributes to ensure the
161
+ The ` #[track_caller] ` attribute is checked alongside other codegen attributes to ensure the
162
162
function:
163
163
164
164
* has the ` "Rust" ` ABI (as opposed to e.g., ` "C" ` )
@@ -173,7 +173,7 @@ used in both const and codegen contexts to ensure correct propagation.
173
173
174
174
When applied to trait method implementations, the attribute works as it does for regular functions.
175
175
176
- When applied to a trait method prototype, the attribute applies to all implementations of the
176
+ When applied to a trait method prototype, the attribute applies to all implementations of the
177
177
method. When applied to a default trait method implementation, the attribute takes effect on
178
178
that implementation * and* any overrides.
179
179
@@ -205,14 +205,14 @@ trait TrackedFourWays {
205
205
assert_tracked! ();
206
206
}
207
207
208
- /// Overrides of this implementation are tracked (it is too).
208
+ /// Overrides of this implementation are tracked (it is too).
209
209
#[track_caller]
210
210
fn default_tracked_to_override () {
211
211
assert_tracked! ();
212
212
}
213
213
}
214
214
215
- /// This impl uses the default impl for `default_tracked` and provides its own for
215
+ /// This impl uses the default impl for `default_tracked` and provides its own for
216
216
/// `default_tracked_to_override`.
217
217
impl TrackedFourWays for () {
218
218
fn blanket_tracked () {
@@ -255,7 +255,7 @@ up on the tracking issue. During the course of implementing that, it was also di
255
255
implementation was possible without modifying the number of arguments in a function's MIR, which
256
256
would simplify later stages and unlock use in traits.
257
257
258
- Because the RFC's implementation strategy could not readily support traits, the semantics were not
258
+ Because the RFC's implementation strategy could not readily support traits, the semantics were not
259
259
originally specified. They have since been implemented following the path which seemed most correct
260
260
to the author and reviewers.
261
261
0 commit comments