Make FatalErrorMarker lower priority than other panics

This commit is contained in:
John Kåre Alsaker 2023-11-03 10:56:30 +01:00
parent 1d6f05fd37
commit ff1858e2aa
3 changed files with 30 additions and 14 deletions

View File

@ -127,6 +127,9 @@ fn drop(&mut self) {
} }
} }
/// This is a marker for a fatal compiler error used with `resume_unwind`.
pub struct FatalErrorMarker;
/// Turns a closure that takes an `&mut Formatter` into something that can be display-formatted. /// Turns a closure that takes an `&mut Formatter` into something that can be display-formatted.
pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display { pub fn make_display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
struct Printer<F> { struct Printer<F> {

View File

@ -3,6 +3,8 @@
#![allow(dead_code)] #![allow(dead_code)]
use crate::sync::IntoDynSyncSend;
use crate::FatalErrorMarker;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::any::Any; use std::any::Any;
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
@ -18,14 +20,17 @@
/// continuing with unwinding. It's also used for the non-parallel code to ensure error message /// continuing with unwinding. It's also used for the non-parallel code to ensure error message
/// output match the parallel compiler for testing purposes. /// output match the parallel compiler for testing purposes.
pub struct ParallelGuard { pub struct ParallelGuard {
panic: Mutex<Option<Box<dyn Any + Send + 'static>>>, panic: Mutex<Option<IntoDynSyncSend<Box<dyn Any + Send + 'static>>>>,
} }
impl ParallelGuard { impl ParallelGuard {
pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> { pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
catch_unwind(AssertUnwindSafe(f)) catch_unwind(AssertUnwindSafe(f))
.map_err(|err| { .map_err(|err| {
*self.panic.lock() = Some(err); let mut panic = self.panic.lock();
if panic.is_none() || !(*err).is::<FatalErrorMarker>() {
*panic = Some(IntoDynSyncSend(err));
}
}) })
.ok() .ok()
} }
@ -37,7 +42,7 @@ pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R { pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
let guard = ParallelGuard { panic: Mutex::new(None) }; let guard = ParallelGuard { panic: Mutex::new(None) };
let ret = f(&guard); let ret = f(&guard);
if let Some(panic) = guard.panic.into_inner() { if let Some(IntoDynSyncSend(panic)) = guard.panic.into_inner() {
resume_unwind(panic); resume_unwind(panic);
} }
ret ret
@ -106,14 +111,20 @@ macro_rules! parallel {
parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
}; };
(impl $fblock:block [$($blocks:expr,)*] []) => { (impl $fblock:block [$($blocks:expr,)*] []) => {
::rustc_data_structures::sync::scope(|s| { $crate::sync::parallel_guard(|guard| {
$(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); $crate::sync::scope(|s| {
s.spawn(move |_| block.into_inner()());)* $(
(|| $fblock)(); let block = $crate::sync::FromDyn::from(|| $blocks);
s.spawn(move |_| {
guard.run(move || block.into_inner()());
});
)*
guard.run(|| $fblock);
});
}); });
}; };
($fblock:block, $($blocks:block),*) => { ($fblock:block, $($blocks:block),*) => {
if rustc_data_structures::sync::is_dyn_thread_safe() { if $crate::sync::is_dyn_thread_safe() {
// Reverse the order of the later blocks since Rayon executes them in reverse order // Reverse the order of the later blocks since Rayon executes them in reverse order
// when using a single thread. This ensures the execution order matches that // when using a single thread. This ensures the execution order matches that
// of a single threaded rustc. // of a single threaded rustc.
@ -146,11 +157,13 @@ pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
if mode::is_dyn_thread_safe() { if mode::is_dyn_thread_safe() {
let oper_a = FromDyn::from(oper_a); let oper_a = FromDyn::from(oper_a);
let oper_b = FromDyn::from(oper_b); let oper_b = FromDyn::from(oper_b);
let (a, b) = rayon::join( let (a, b) = parallel_guard(|guard| {
move || FromDyn::from(oper_a.into_inner()()), rayon::join(
move || FromDyn::from(oper_b.into_inner()()), move || guard.run(move || FromDyn::from(oper_a.into_inner()())),
); move || guard.run(move || FromDyn::from(oper_b.into_inner()())),
(a.into_inner(), b.into_inner()) )
});
(a.unwrap().into_inner(), b.unwrap().into_inner())
} else { } else {
super::disabled::join(oper_a, oper_b) super::disabled::join(oper_a, oper_b)
} }

View File

@ -5,7 +5,7 @@
#[must_use] #[must_use]
pub struct FatalError; pub struct FatalError;
pub struct FatalErrorMarker; pub use rustc_data_structures::FatalErrorMarker;
// Don't implement Send on FatalError. This makes it impossible to panic!(FatalError). // Don't implement Send on FatalError. This makes it impossible to panic!(FatalError).
// We don't want to invoke the panic handler and print a backtrace for fatal errors. // We don't want to invoke the panic handler and print a backtrace for fatal errors.