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
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
//! 标准库中的 Panic 支持。

#![stable(feature = "std_panic", since = "1.9.0")]

use crate::any::Any;
use crate::collections;
use crate::panicking;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::{Mutex, RwLock};
use crate::thread::Result;

#[doc(hidden)]
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic, rt)]
#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")]
#[rustc_macro_transparency = "semitransparent"]
pub macro panic_2015 {
    () => ({
        $crate::rt::begin_panic("explicit panic")
    }),
    ($msg:expr $(,)?) => ({
        $crate::rt::begin_panic($msg);
    }),
    // 特殊情况下 const_panic 的单个参数情况。
    ("{}", $arg:expr $(,)?) => ({
        $crate::rt::panic_display(&$arg);
    }),
    ($fmt:expr, $($arg:tt)+) => ({
        // 分号,以防止在 panic_fmt 调用后调用者认为格式化机器内的临时对象还活着。
        //
        $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+));
    }),
}

#[doc(hidden)]
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
pub use core::panic::panic_2021;

#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use crate::panicking::{set_hook, take_hook};

#[unstable(feature = "panic_update_hook", issue = "92649")]
pub use crate::panicking::update_hook;

#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use core::panic::{Location, PanicInfo};

#[stable(feature = "catch_unwind", since = "1.9.0")]
pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};

/// 使用给定的消息作为 panic 有效载荷,使当前线程 panic。
///
/// 该消息可以是任何 (`Any + Send`) 类型,而不仅仅是字符串。
///
/// 该消息包装在一个 `Box<'static + Any + Send>` 中,以后可以使用 [`PanicInfo::payload`] 访问它。
///
///
/// 有关 panic 的更多信息,请参见 [`panic!`] 宏。
#[stable(feature = "panic_any", since = "1.51.0")]
#[inline]
#[track_caller]
pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
    crate::panicking::begin_panic(msg);
}

#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> UnwindSafe for Mutex<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> UnwindSafe for RwLock<T> {}

#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}

// https://github.com/rust-lang/rust/issues/62301
#[stable(feature = "hashbrown", since = "1.36.0")]
impl<K, V, S> UnwindSafe for collections::HashMap<K, V, S>
where
    K: UnwindSafe,
    V: UnwindSafe,
    S: UnwindSafe,
{
}

/// 调用一个闭包,如果发生,则捕获展开 panic 的原因。
///
/// 如果闭包不是 panic,则此函数将返回 `Ok`,并返回闭包的结果; 如果闭包 panics,则此函数将返回 `Err(cause)`。
/// 返回的 `cause` 是最初调用 panic 的对象。
///
/// unwind 当前从 Rust 代码转换为外来代码是未定义的行为,因此当从另一种语言 (通常为 C) 调用 Rust 时,此函数特别有用。
/// 这可以运行任意的 Rust 代码,捕获 panic 并允许对错误进行适当的处理。
///
/// 不建议将此函数用于一般的 try/catch 机制。[`Result`] 类型更适合用于经常失败的函数。
/// 此外,不能保证此函数可以捕获所有 panics,请参见下面的 "Notes" 部分。
///
/// 提供的闭包必须遵守 [`UnwindSafe`] trait,以确保所有捕获的变量都可以安全越过此边界。
/// 此绑定的目的是在类型系统中对 [异常安全][rfc] 的概念进行编码。
/// 此函数的大多数用法都不必担心此绑定,因为没有 `unsafe` 代码的程序自然是 unwind 安全的。
/// 如果出现问题,可以使用 [`AssertUnwindSafe`] 包装器结构体快速断言此处的使用确实是 unwind 安全的。
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// # Notes
///
/// 请注意,此函数**可能无法捕获 Rust 中的所有 panics**。Rust 中的 panic 并不总是通过展开来实现,但是也可以通过中止进程来实现。
///
/// 该函数 *仅* 捕获展开 panics,而不是那些中止进程的 panics。
///
/// 请注意,如果已设置自定义 panic 钩子,它将在 panic 被捕获之前调用,在展开之前。
///
/// 另请注意,使用外部异常 (例如,展开为 Rust 代码)
/// 从 C++ 代码引发的异常) 是未定义的行为。
///
/// # Examples
///
/// ```
/// use std::panic;
///
/// let result = panic::catch_unwind(|| {
///     println!("hello!");
/// });
/// assert!(result.is_ok());
///
/// let result = panic::catch_unwind(|| {
///     panic!("oh no!");
/// });
/// assert!(result.is_err());
/// ```
///
///
///
///
///
///
///
///
///
///
#[stable(feature = "catch_unwind", since = "1.9.0")]
pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
    unsafe { panicking::r#try(f) }
}

/// 在不调用 panic 钩子的情况下触发 panic。
///
/// 它被设计为与 [`catch_unwind`] 结合使用,例如,跨 C 代码层携带 panic。
///
/// # Notes
///
/// 请注意,Rust 中的 panics 并不总是通过展开来实现,但是可以通过中止进程来实现。
/// 如果以这种方式实现 panics 时调用了此函数,则此函数将中止进程,而不触发 unwind。
///
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// let result = panic::catch_unwind(|| {
///     panic!("oh no!");
/// });
///
/// if let Err(err) = result {
///     panic::resume_unwind(err);
/// }
/// ```
///
///
#[stable(feature = "resume_unwind", since = "1.9.0")]
pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
    panicking::rust_panic_without_hook(payload)
}

/// 使所有未来的 panic 直接中止,而不运行 panic 钩子或展开。
///
/// 没有办法撤销这个; 效果持续到进程退出或执行 (或等效)。
///
/// # fork 后使用
///
/// 这个函数在 `libc::fork` 之后调用特别有用。在 `fork` 之后,在多线程程序中 (在许多平台上) 调用分配器是不安全的。
/// `fork` 之后的 unwind 到 unwind 通常也是非常不可取的,因为这会导致 unwind 传播到只希望在父级中运行的代码。
///
///
/// `panic::always_abort()` 有助于避免这两种情况。
/// 它直接避免了任何进一步的展开,如果存在 panic,则无需分配即可中止中止,前提是 panic 的参数可以在不分配的情况下进行格式化。
///
/// Examples
///
/// ```no_run
/// #![feature(panic_always_abort)]
/// use std::panic;
///
/// panic::always_abort();
///
/// let _ = panic::catch_unwind(|| {
///     panic!("inside the catch");
/// });
///
/// // 由于 panic,我们已经中止了。
/// unreachable!();
/// ```
///
///
///
#[unstable(feature = "panic_always_abort", issue = "84438")]
pub fn always_abort() {
    crate::panicking::panic_count::set_always_abort();
}

/// 默认 panic 钩子,是否以及如何捕获和显示回溯的配置。
///
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "panic_backtrace_config", issue = "93346")]
#[non_exhaustive]
pub enum BacktraceStyle {
    /// 打印一个简洁的回溯,理想情况下只包含相关信息。
    ///
    Short,
    /// 打印包含所有可能信息的回溯。
    Full,
    /// 禁用收集和显示回溯。
    Off,
}

impl BacktraceStyle {
    pub(crate) fn full() -> Option<Self> {
        if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None }
    }

    fn as_usize(self) -> usize {
        match self {
            BacktraceStyle::Short => 1,
            BacktraceStyle::Full => 2,
            BacktraceStyle::Off => 3,
        }
    }

    fn from_usize(s: usize) -> Option<Self> {
        Some(match s {
            0 => return None,
            1 => BacktraceStyle::Short,
            2 => BacktraceStyle::Full,
            3 => BacktraceStyle::Off,
            _ => unreachable!(),
        })
    }
}

// 跟踪我们是否应该或能够捕获回溯,以及我们应该如何显示回溯。
//
//
// 内部存储相当于 Option<BacktraceStyle>。
static SHOULD_CAPTURE: AtomicUsize = AtomicUsize::new(0);

/// 配置默认的 panic 钩子,是否将捕获并显示回溯。
///
/// 此设置的默认值可以由 `RUST_BACKTRACE` 环境变量设置; 请参见 [`get_backtrace_style`] 中的详细信息。
///
///
#[unstable(feature = "panic_backtrace_config", issue = "93346")]
pub fn set_backtrace_style(style: BacktraceStyle) {
    if !cfg!(feature = "backtrace") {
        // 如果此 crate 的 `backtrace` 特性没有被启用,请跳过设置。
        return;
    }
    SHOULD_CAPTURE.store(style.as_usize(), Ordering::Release);
}

/// 检查标准库的 panic 钩子是否会捕获并打印回溯。
///
/// 如果没有通过 [`set_backtrace_style`] 设置回溯样式,此函数将读取环境变量 `RUST_BACKTRACE` 以确定回溯格式的默认值:
///
///
/// 如果没有调用 `set_backtrace_style` 来覆盖默认值,则对 `get_backtrace_style` 的第一个调用可能会读取 `RUST_BACKTRACE` 环境变量。
/// 调用 `set_backtrace_style` 或 `get_backtrace_style` 后,对 `RUST_BACKTRACE` 的任何更改都将无效。
///
/// `RUST_BACKTRACE` 根据以下规则读取:
///
/// * `0` 代表 `BacktraceStyle::Off`
/// * `full` 代表 `BacktraceStyle::Full`
/// * `1` 代表 `BacktraceStyle::Short`
/// * 其他值目前是 `BacktraceStyle::Short`,但这可能会在未来改变
///
/// 如果当前不支持回溯,则返回 `None`。
///
///
///
///
///
#[unstable(feature = "panic_backtrace_config", issue = "93346")]
pub fn get_backtrace_style() -> Option<BacktraceStyle> {
    if !cfg!(feature = "backtrace") {
        // 如果未启用此 crate 的 `backtrace` 特性,请快速返回 `Unsupported`,这样就可以在整个地方不断传播,以优化离开的调用者。
        //
        //
        return None;
    }
    if let Some(style) = BacktraceStyle::from_usize(SHOULD_CAPTURE.load(Ordering::Acquire)) {
        return Some(style);
    }

    let format = crate::env::var_os("RUST_BACKTRACE")
        .map(|x| {
            if &x == "0" {
                BacktraceStyle::Off
            } else if &x == "full" {
                BacktraceStyle::Full
            } else {
                BacktraceStyle::Short
            }
        })
        .unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT {
            BacktraceStyle::Full
        } else {
            BacktraceStyle::Off
        });
    set_backtrace_style(format);
    Some(format)
}

#[cfg(test)]
mod tests;