1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//! 核心上的 panic 支持
//!
//! 核心库无法定义 panic,但可以声明 panic。
//! 这意味着允许内核中的函数 panic,但要有用,上游 crate 必须定义内核使用的 panicing。
//! 当前的 panic 接口是:
//!
//! ```
//! fn panic_impl(pi: &core::panic::PanicInfo<'_>) -> !
//! # { loop {} }
//! ```
//!
//! 此定义允许对任何常规消息进行 panic,但不允许 `Box<Any>` 值失败。
//! (`PanicInfo` 只包含一个 `&(dyn Any + Send)`,为此我们在 PanicInfo::internal_constructor 中为其填充了一个虚拟值。) 这样做的原因是核心不允许分配。
//!
//!
//! 该模块还包含其他一些紧急函数,但这只是编译器必需的 lang 项。所有 panics 都通过此函数进行了分配。
//! 实际符号通过 `#[panic_handler]` 属性声明。
//!
//!
//!

#![allow(dead_code, missing_docs)]
#![unstable(
    feature = "core_panic",
    reason = "internal details of the implementation of the `panic!` and related macros",
    issue = "none"
)]

use crate::fmt;
use crate::panic::{Location, PanicInfo};

#[cfg(feature = "panic_immediate_abort")]
const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort");

// 首先,我们定义所有 panic 都会经历的两个主要入口点。
// 最后,两者都只是 `panic_impl` 的便利包装。

/// 带有格式化消息的 panic 的入口点。
///
/// 通过将实际格式移到该共享位置,可以最大程度地减少调用站点上所需的代码量 (以使 `panic!()` 对 (e.g.) 内联其他函数的影响尽可能小)。
///
///
///
// 如果使用 panic_immediate_abort,则内联中止调用,否则请避免内联,因为它是冷路径。
//
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[lang = "panic_fmt"] // 常量评估的 panics 所需
#[rustc_do_not_const_check] // 被 const-eval 钩住了
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        super::intrinsics::abort()
    }

    // NOTE 这个函数永远不会越过 FFI 边界。这是 Rust 到 Rust 调用,已解析为 `#[panic_handler]` 函数。
    //
    extern "Rust" {
        #[lang = "panic_impl"]
        fn panic_impl(pi: &PanicInfo<'_>) -> !;
    }

    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);

    // SAFETY: `panic_impl` 在安全的 Rust 代码中定义,因此可以安全调用。
    unsafe { panic_impl(&pi) }
}

/// 像 `panic_fmt`,但用于非展开 panic。
///
/// 必须是一个单独的函数,以便它可以携带 `rustc_nounwind` 属性。
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
// 这个属性有一个关键的副作用,如果 panic 处理程序忽略 `can_unwind` 并无论如何展开,我们将攻击 "unwinding out of nounwind function" 守卫,这会导致 "panic in a function that cannot unwind"。
//
//
#[rustc_nounwind]
pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        super::intrinsics::abort()
    }

    // NOTE 这个函数永远不会越过 FFI 边界。这是 Rust 到 Rust 调用,已解析为 `#[panic_handler]` 函数。
    //
    extern "Rust" {
        #[lang = "panic_impl"]
        fn panic_impl(pi: &PanicInfo<'_>) -> !;
    }

    // 将 `can_unwind` 标志设置为 false 的 PanicInfo 会强制中止。
    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);

    // SAFETY: `panic_impl` 在安全的 Rust 代码中定义,因此可以安全调用。
    unsafe { panic_impl(&pi) }
}

// 接下来我们在上面的两个核心函数中定义了一堆更高级别的包装器。
//

/// 不使用格式化时核心的 `panic!` 宏的底层实现。
// 从不内联,除非 panic_immediate_abort 尽可能避免代码在调用站点上膨胀
//
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
#[lang = "panic"] // 溢出和其他 `Assert` MIR 终结器时 panic 的代码生成所需的
pub const fn panic(expr: &'static str) -> ! {
    // 使用 Arguments::new_v1 而不是 format_args!("{expr}") 可能会减少大小开销。
    // The format_args!  宏使用 str 的 Display trait 来编写 expr,它调用 Formatter::pad,它必须适应字符串截断和填充 (尽管这里没有使用任何内容)。
    //
    // 使用 Arguments::new_v1 可使编译器从输出二进制文件中省略 Formatter::pad,从而节省多达几千字节的空间。
    //
    //
    panic_fmt(fmt::Arguments::new_const(&[expr]));
}

/// 像 `panic`,但没有展开和 track_caller 以减少对代码大小的影响。
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[lang = "panic_nounwind"] // codegen 需要用于非展开 panic
#[rustc_nounwind]
pub fn panic_nounwind(expr: &'static str) -> ! {
    panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]));
}

#[inline]
#[track_caller]
#[rustc_diagnostic_item = "panic_str"]
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_str(expr: &str) -> ! {
    panic_display(&expr);
}

#[inline]
#[track_caller]
#[rustc_diagnostic_item = "unreachable_display"] // `non-fmt-panics` lint 需要
pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
    panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
}

#[inline]
#[track_caller]
#[lang = "panic_display"] // 常量评估的 panics 所需
#[rustc_do_not_const_check] // 被 const-eval 钩住了
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
    panic_fmt(format_args!("{}", *x));
}

#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[lang = "panic_bounds_check"] // OOB array/slice 访问上 panic 的代码生成所需的
fn panic_bounds_check(index: usize, len: usize) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        super::intrinsics::abort()
    }

    panic!("index out of bounds: the len is {len} but the index is {index}")
}

#[cold]
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[track_caller]
#[lang = "panic_misaligned_pointer_dereference"] // codegen 需要对未对齐的指针 deref 进行 panic
fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        super::intrinsics::abort()
    }

    panic!(
        "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
    )
}

/// panic 是因为我们无法从函数中解脱出来。
///
/// 这个函数由 codegen 后端直接调用,并且不能有任何额外的参数 (包括那些由 track_caller 合成的参数)。
///
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[lang = "panic_cannot_unwind"] // odegen 需要在 nounwind 函数中出现 panic
#[rustc_nounwind]
fn panic_cannot_unwind() -> ! {
    panic_nounwind("panic in a function that cannot unwind")
}

/// 在 const eval 中使用此函数代替 panic_fmt。
#[lang = "const_panic_fmt"]
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
    if let Some(msg) = fmt.as_str() {
        panic_str(msg);
    } else {
        // SAFETY: 这仅在编译时评估,它可靠地处理此 UB (以防此分支以某种方式可达)。
        //
        //
        unsafe { crate::hint::unreachable_unchecked() };
    }
}

#[derive(Debug)]
#[doc(hidden)]
pub enum AssertKind {
    Eq,
    Ne,
    Match,
}

/// `assert_eq!` 和 `assert_ne!` 宏的内联函数
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[doc(hidden)]
pub fn assert_failed<T, U>(
    kind: AssertKind,
    left: &T,
    right: &U,
    args: Option<fmt::Arguments<'_>>,
) -> !
where
    T: fmt::Debug + ?Sized,
    U: fmt::Debug + ?Sized,
{
    assert_failed_inner(kind, &left, &right, args)
}

/// `assert_match!` 的内联函数
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[doc(hidden)]
pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
    left: &T,
    right: &str,
    args: Option<fmt::Arguments<'_>>,
) -> ! {
    // 该模式是一个字符串,因此可以直接显示。
    struct Pattern<'a>(&'a str);
    impl fmt::Debug for Pattern<'_> {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str(self.0)
        }
    }
    assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
}

/// 上述函数的非泛型版本,以避免代码膨胀。
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
fn assert_failed_inner(
    kind: AssertKind,
    left: &dyn fmt::Debug,
    right: &dyn fmt::Debug,
    args: Option<fmt::Arguments<'_>>,
) -> ! {
    let op = match kind {
        AssertKind::Eq => "==",
        AssertKind::Ne => "!=",
        AssertKind::Match => "matches",
    };

    match args {
        Some(args) => panic!(
            r#"assertion failed: `(left {} right)`
  left: `{:?}`,
 right: `{:?}`: {}"#,
            op, left, right, args
        ),
        None => panic!(
            r#"assertion failed: `(left {} right)`
  left: `{:?}`,
 right: `{:?}`"#,
            op, left, right,
        ),
    }
}