mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-15 06:33:58 +00:00
Handle panicking like rustc CTFE does
Instead of using `core::fmt::format` to format panic messages, which may in turn panic too and cause recursive panics and other messy things, redirect `panic_fmt` to `const_panic_fmt` like CTFE, which in turn goes to `panic_display` and does the things normally. See the tests for the full call stack.
This commit is contained in:
parent
062e1b9b81
commit
805f569adc
2 changed files with 63 additions and 8 deletions
|
@ -31,6 +31,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
|
||||||
db.trait_environment(func_id.into()),
|
db.trait_environment(func_id.into()),
|
||||||
)
|
)
|
||||||
.map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
|
.map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
|
||||||
|
|
||||||
let (result, output) = interpret_mir(db, body, false, None);
|
let (result, output) = interpret_mir(db, body, false, None);
|
||||||
result?;
|
result?;
|
||||||
Ok((output.stdout().into_owned(), output.stderr().into_owned()))
|
Ok((output.stdout().into_owned(), output.stderr().into_owned()))
|
||||||
|
@ -87,6 +88,42 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn panic_fmt() {
|
||||||
|
// panic!
|
||||||
|
// -> panic_2021 (builtin macro redirection)
|
||||||
|
// -> #[lang = "panic_fmt"] core::panicking::panic_fmt (hooked by CTFE for redirection)
|
||||||
|
// -> core::panicking::const_panic_fmt
|
||||||
|
// -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
|
||||||
|
// -> Err(ConstEvalError::Panic)
|
||||||
|
check_pass(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt, panic
|
||||||
|
fn main() {
|
||||||
|
panic!("hello, world!");
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
panic!("a");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn panic_display() {
|
||||||
|
// panic!
|
||||||
|
// -> panic_2021 (builtin macro redirection)
|
||||||
|
// -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
|
||||||
|
// -> Err(ConstEvalError::Panic)
|
||||||
|
check_pass(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt, panic
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
panic!("{}", "hello, world!");
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drop_basic() {
|
fn drop_basic() {
|
||||||
check_pass(
|
check_pass(
|
||||||
|
|
|
@ -1356,18 +1356,36 @@ pub mod iter {
|
||||||
// region:panic
|
// region:panic
|
||||||
mod panic {
|
mod panic {
|
||||||
pub macro panic_2021 {
|
pub macro panic_2021 {
|
||||||
() => (
|
() => ({
|
||||||
$crate::panicking::panic("explicit panic")
|
const fn panic_cold_explicit() -> ! {
|
||||||
),
|
$crate::panicking::panic_explicit()
|
||||||
($($t:tt)+) => (
|
}
|
||||||
$crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
|
panic_cold_explicit();
|
||||||
),
|
}),
|
||||||
|
// Special-case the single-argument case for const_panic.
|
||||||
|
("{}", $arg:expr $(,)?) => ({
|
||||||
|
#[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
|
||||||
|
const fn panic_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
panic_cold_display(&$arg);
|
||||||
|
}),
|
||||||
|
($($t:tt)+) => ({
|
||||||
|
// Semicolon to prevent temporaries inside the formatting machinery from
|
||||||
|
// being considered alive in the caller after the panic_fmt call.
|
||||||
|
$crate::panicking::panic_fmt($crate::const_format_args!($($t)+));
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod panicking {
|
mod panicking {
|
||||||
#[lang = "panic_fmt"]
|
#[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
|
||||||
pub const fn panic_fmt(_fmt: crate::fmt::Arguments<'_>) -> ! {
|
pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
|
||||||
|
panic_fmt(format_args!("{}", *x));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "panic_fmt"] // needed for const-evaluated panics
|
||||||
|
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue