mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 15:14:32 +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()),
|
||||
)
|
||||
.map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
|
||||
|
||||
let (result, output) = interpret_mir(db, body, false, None);
|
||||
result?;
|
||||
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]
|
||||
fn drop_basic() {
|
||||
check_pass(
|
||||
|
|
|
@ -1356,18 +1356,36 @@ pub mod iter {
|
|||
// region:panic
|
||||
mod panic {
|
||||
pub macro panic_2021 {
|
||||
() => (
|
||||
$crate::panicking::panic("explicit panic")
|
||||
),
|
||||
($($t:tt)+) => (
|
||||
$crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
|
||||
),
|
||||
() => ({
|
||||
const fn panic_cold_explicit() -> ! {
|
||||
$crate::panicking::panic_explicit()
|
||||
}
|
||||
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 {
|
||||
#[lang = "panic_fmt"]
|
||||
pub const fn panic_fmt(_fmt: crate::fmt::Arguments<'_>) -> ! {
|
||||
#[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
|
||||
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 {}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue