Skip to content

Commit 9739d3a

Browse files
committed
sembr src/panic-implementation.md
1 parent 7fcb691 commit 9739d3a

1 file changed

Lines changed: 32 additions & 22 deletions

File tree

src/panic-implementation.md

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
## Step 1: Invocation of the `panic!` macro.
44

55
There are actually two panic macros - one defined in `core`, and one defined in `std`.
6-
This is due to the fact that code in `core` can panic. `core` is built before `std`,
7-
but we want panics to use the same machinery at runtime, whether they originate in `core`
8-
or `std`.
6+
This is due to the fact that code in `core` can panic.
7+
`core` is built before `std`,
8+
but we want panics to use the same machinery at runtime, whether they originate in `core` or `std`.
99

1010
### core definition of panic!
1111

@@ -30,8 +30,8 @@ unsafe { panic_impl(&pi) }
3030
Actually resolving this goes through several layers of indirection:
3131

3232
1. In [`compiler/rustc_hir/src/weak_lang_items.rs`], `panic_impl` is
33-
declared as 'weak lang item', with the symbol `rust_begin_unwind`. This is
34-
used in `rustc_hir_analysis/src/collect.rs` to set the actual symbol name to
33+
declared as 'weak lang item', with the symbol `rust_begin_unwind`.
34+
This is used in `rustc_hir_analysis/src/collect.rs` to set the actual symbol name to
3535
`rust_begin_unwind`.
3636

3737
Note that `panic_impl` is declared in an `extern "Rust"` block,
@@ -52,26 +52,33 @@ pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
5252
The special `panic_handler` attribute is resolved via [`compiler/rustc_passes/src/lang_items.rs`].
5353
The [`extract_ast`] function converts the `panic_handler` attribute to a `panic_impl` lang item.
5454

55-
Now, we have a matching `panic_handler` lang item in the `std`. This function goes
55+
Now, we have a matching `panic_handler` lang item in the `std`.
56+
This function goes
5657
through the same process as the `extern { fn panic_impl }` definition in `core`, ending
57-
up with a symbol name of `rust_begin_unwind`. At link time, the symbol reference in `core`
58+
up with a symbol name of `rust_begin_unwind`.
59+
At link time, the symbol reference in `core`
5860
will be resolved to the definition of `std` (the function called `panic_handler` in the
5961
Rust source).
6062

61-
Thus, control flow will pass from core to std at runtime. This allows panics from `core`
63+
Thus, control flow will pass from core to std at runtime.
64+
This allows panics from `core`
6265
to go through the same infrastructure that other panics use (panic hooks, unwinding, etc)
6366

6467
### std implementation of panic!
6568

66-
This is where the actual panic-related logic begins. In [`library/std/src/panicking.rs`],
67-
control passes to `panic_with_hook`. This method is responsible
68-
for invoking the global panic hook, and checking for double panics. Finally,
69+
This is where the actual panic-related logic begins.
70+
In [`library/std/src/panicking.rs`],
71+
control passes to `panic_with_hook`.
72+
This method is responsible for invoking the global panic hook, and checking for double panics.
73+
Finally,
6974
we call `__rust_start_panic`, which is provided by the panic runtime.
7075

7176
The call to `__rust_start_panic` is very weird - it is passed a `*mut &mut dyn PanicPayload`,
72-
converted to an `usize`. Let's break this type down:
77+
converted to an `usize`.
78+
Let's break this type down:
7379

74-
1. `PanicPayload` is an internal trait. It is implemented for `PanicPayload`
80+
1. `PanicPayload` is an internal trait.
81+
It is implemented for `PanicPayload`
7582
(a wrapper around the user-supplied payload type), and has a method
7683
`fn take_box(&mut self) -> *mut (dyn Any + Send)`.
7784
This method takes the user-provided payload (`T: Any + Send`),
@@ -81,16 +88,18 @@ boxes it, and converts the box to a raw pointer.
8188
However, this is a fat pointer (twice the size of a `usize`).
8289
To pass this to the panic runtime across an FFI boundary, we take a mutable
8390
reference *to this mutable reference* (`&mut &mut dyn PanicPayload`), and convert it to a raw
84-
pointer (`*mut &mut dyn PanicPayload`). The outer raw pointer is a thin pointer, since it points to
85-
a `Sized` type (a mutable reference). Therefore, we can convert this thin pointer into a `usize`,
91+
pointer (`*mut &mut dyn PanicPayload`).
92+
The outer raw pointer is a thin pointer, since it points to a `Sized` type (a mutable reference).
93+
Therefore, we can convert this thin pointer into a `usize`,
8694
which is suitable for passing across an FFI boundary.
8795

88-
Finally, we call `__rust_start_panic` with this `usize`. We have now entered the panic runtime.
96+
Finally, we call `__rust_start_panic` with this `usize`.
97+
We have now entered the panic runtime.
8998

9099
## Step 2: The panic runtime
91100

92-
Rust provides two panic runtimes: `panic_abort` and `panic_unwind`. The user chooses
93-
between them at build time via their `Cargo.toml`
101+
Rust provides two panic runtimes: `panic_abort` and `panic_unwind`.
102+
The user chooses between them at build time via their `Cargo.toml`
94103

95104
`panic_abort` is extremely simple: its implementation of `__rust_start_panic` just aborts,
96105
as you would expect.
@@ -99,13 +108,14 @@ as you would expect.
99108

100109
In its implementation of `__rust_start_panic`, we take the `usize`, convert
101110
it back to a `*mut &mut dyn PanicPayload`, dereference it, and call `take_box`
102-
on the `&mut dyn PanicPayload`. At this point, we have a raw pointer to the payload
111+
on the `&mut dyn PanicPayload`.
112+
At this point, we have a raw pointer to the payload
103113
itself (a `*mut (dyn Send + Any)`): that is, a raw pointer to the actual value
104114
provided by the user who called `panic!`.
105115

106-
At this point, the platform-independent code ends. We now call into
107-
platform-specific unwinding logic (e.g `unwind`). This code is
108-
responsible for unwinding the stack, running any 'landing pads' associated
116+
At this point, the platform-independent code ends.
117+
We now call into platform-specific unwinding logic (e.g `unwind`).
118+
This code is responsible for unwinding the stack, running any 'landing pads' associated
109119
with each frame (currently, running destructors), and transferring control
110120
to the `catch_unwind` frame.
111121

0 commit comments

Comments
 (0)