Skip to content

Commit c5d42b1

Browse files
committed
Ensure all iterations in Rayon iterators run in the presence of panics
1 parent 9fe05e9 commit c5d42b1

File tree

8 files changed

+94
-64
lines changed

8 files changed

+94
-64
lines changed

src/librustc/hir/map/hir_id_validator.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::hir::map::Map;
22
use rustc_data_structures::fx::FxHashSet;
3-
use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
3+
use rustc_data_structures::sync::{par_for_each, Lock};
44
use rustc_hir as hir;
55
use rustc_hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
66
use rustc_hir::intravisit;
@@ -12,7 +12,7 @@ pub fn check_crate(hir_map: &Map<'_>) {
1212

1313
let errors = Lock::new(Vec::new());
1414

15-
par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
15+
par_for_each(&hir_map.krate().modules, |(module_id, _)| {
1616
let local_def_id = hir_map.local_def_id(*module_id);
1717
hir_map.visit_item_likes_in_module(
1818
local_def_id,

src/librustc/ty/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_data_structures::captures::Captures;
3030
use rustc_data_structures::fx::FxHashMap;
3131
use rustc_data_structures::fx::FxIndexMap;
3232
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
33-
use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator};
33+
use rustc_data_structures::sync::{self, par_for_each, Lrc};
3434
use rustc_hir as hir;
3535
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
3636
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -2642,8 +2642,9 @@ impl<'tcx> TyCtxt<'tcx> {
26422642
}
26432643

26442644
pub fn par_body_owners<F: Fn(DefId) + sync::Sync + sync::Send>(self, f: F) {
2645-
par_iter(&self.hir().krate().body_ids)
2646-
.for_each(|&body_id| f(self.hir().body_owner_def_id(body_id)));
2645+
par_for_each(&self.hir().krate().body_ids, |&body_id| {
2646+
f(self.hir().body_owner_def_id(body_id))
2647+
});
26472648
}
26482649

26492650
pub fn provided_trait_methods(self, id: DefId) -> Vec<AssocItem> {

src/librustc_codegen_ssa/base.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use rustc::ty::{self, Instance, Ty, TyCtxt};
4040
use rustc_codegen_utils::{check_for_rustc_errors_attr, symbol_names_test};
4141
use rustc_data_structures::fx::FxHashMap;
4242
use rustc_data_structures::profiling::print_time_passes_entry;
43-
use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
43+
use rustc_data_structures::sync::{par_map, Lock};
4444
use rustc_hir as hir;
4545
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
4646
use rustc_index::vec::Idx;
@@ -631,15 +631,13 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
631631
.collect();
632632

633633
// Compile the found CGUs in parallel.
634-
par_iter(cgus)
635-
.map(|(i, _)| {
636-
let start_time = Instant::now();
637-
let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
638-
let mut time = total_codegen_time.lock();
639-
*time += start_time.elapsed();
640-
(i, module)
641-
})
642-
.collect()
634+
par_map(cgus, |(i, _)| {
635+
let start_time = Instant::now();
636+
let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
637+
let mut time = total_codegen_time.lock();
638+
*time += start_time.elapsed();
639+
(i, module)
640+
})
643641
})
644642
} else {
645643
FxHashMap::default()

src/librustc_data_structures/sync.rs

+68-37
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,33 @@
1818
//! depending on the value of cfg!(parallel_compiler).
1919
2020
use crate::owning_ref::{Erased, OwningRef};
21+
use std::any::Any;
2122
use std::collections::HashMap;
2223
use std::hash::{BuildHasher, Hash};
2324
use std::marker::PhantomData;
2425
use std::ops::{Deref, DerefMut};
26+
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
2527

2628
pub use std::sync::atomic::Ordering;
2729
pub use std::sync::atomic::Ordering::SeqCst;
2830

31+
pub fn catch<R>(
32+
store: &Lock<Option<Box<dyn Any + std::marker::Send + 'static>>>,
33+
f: impl FnOnce() -> R,
34+
) -> Option<R> {
35+
catch_unwind(AssertUnwindSafe(f))
36+
.map_err(|err| {
37+
*store.lock() = Some(err);
38+
})
39+
.ok()
40+
}
41+
42+
pub fn resume(store: Lock<Option<Box<dyn Any + std::marker::Send + 'static>>>) {
43+
if let Some(panic) = store.into_inner() {
44+
resume_unwind(panic);
45+
}
46+
}
47+
2948
cfg_if! {
3049
if #[cfg(not(parallel_compiler))] {
3150
pub auto trait Send {}
@@ -42,7 +61,6 @@ cfg_if! {
4261
}
4362

4463
use std::ops::Add;
45-
use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
4664

4765
/// This is a single threaded variant of AtomicCell provided by crossbeam.
4866
/// Unlike `Atomic` this is intended for all `Copy` types,
@@ -181,46 +199,40 @@ cfg_if! {
181199
($($blocks:tt),*) => {
182200
// We catch panics here ensuring that all the blocks execute.
183201
// This makes behavior consistent with the parallel compiler.
184-
let mut panic = None;
202+
let panic = ::rustc_data_structures::sync::Lock::new(None);
185203
$(
186-
if let Err(p) = ::std::panic::catch_unwind(
187-
::std::panic::AssertUnwindSafe(|| $blocks)
188-
) {
189-
if panic.is_none() {
190-
panic = Some(p);
191-
}
192-
}
204+
::rustc_data_structures::sync::catch(&panic, || $blocks);
193205
)*
194-
if let Some(panic) = panic {
195-
::std::panic::resume_unwind(panic);
196-
}
206+
::rustc_data_structures::sync::resume(panic);
197207
}
198208
}
199209

200-
pub use std::iter::Iterator as ParallelIterator;
210+
use std::iter::{Iterator, IntoIterator, FromIterator};
201211

202-
pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
203-
t.into_iter()
204-
}
205-
206-
pub fn par_for_each_in<T: IntoIterator>(
212+
pub fn par_for_each<T: IntoIterator>(
207213
t: T,
208-
for_each:
209-
impl Fn(<<T as IntoIterator>::IntoIter as Iterator>::Item) + Sync + Send
214+
mut for_each: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item),
210215
) {
211216
// We catch panics here ensuring that all the loop iterations execute.
212217
// This makes behavior consistent with the parallel compiler.
213-
let mut panic = None;
218+
let panic = Lock::new(None);
214219
t.into_iter().for_each(|i| {
215-
if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) {
216-
if panic.is_none() {
217-
panic = Some(p);
218-
}
219-
}
220+
catch(&panic, || for_each(i));
220221
});
221-
if let Some(panic) = panic {
222-
resume_unwind(panic);
223-
}
222+
resume(panic);
223+
}
224+
225+
pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
226+
t: T,
227+
mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
228+
) -> C {
229+
// We catch panics here ensuring that all the loop iterations execute.
230+
let panic = Lock::new(None);
231+
let r = t.into_iter().filter_map(|i| {
232+
catch(&panic, || map(i))
233+
}).collect();
234+
resume(panic);
235+
r
224236
}
225237

226238
pub type MetadataRef = OwningRef<Box<dyn Erased>, [u8]>;
@@ -388,20 +400,39 @@ cfg_if! {
388400

389401
pub use rayon_core::WorkerLocal;
390402

391-
pub use rayon::iter::ParallelIterator;
392-
use rayon::iter::IntoParallelIterator;
393-
394-
pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter {
395-
t.into_par_iter()
396-
}
403+
use rayon::iter::{ParallelIterator, FromParallelIterator, IntoParallelIterator};
397404

398-
pub fn par_for_each_in<T: IntoParallelIterator>(
405+
pub fn par_for_each<T: IntoParallelIterator>(
399406
t: T,
400407
for_each: impl Fn(
401408
<<T as IntoParallelIterator>::Iter as ParallelIterator>::Item
402409
) + Sync + Send
403410
) {
404-
t.into_par_iter().for_each(for_each)
411+
// We catch panics here ensuring that all the loop iterations execute.
412+
let panic = Lock::new(None);
413+
t.into_par_iter().for_each(|i| {
414+
catch(&panic, || for_each(i));
415+
});
416+
resume(panic);
417+
}
418+
419+
pub fn par_map<
420+
T: IntoParallelIterator,
421+
R: Send,
422+
C: FromParallelIterator<R>
423+
>(
424+
t: T,
425+
map: impl Fn(
426+
<<T as IntoParallelIterator>::Iter as ParallelIterator>::Item
427+
) -> R + Sync + Send
428+
) -> C {
429+
// We catch panics here ensuring that all the loop iterations execute.
430+
let panic = Lock::new(None);
431+
let r = t.into_par_iter().filter_map(|i| {
432+
catch(&panic, || map(i))
433+
}).collect();
434+
resume(panic);
435+
r
405436
}
406437

407438
pub type MetadataRef = OwningRef<Box<dyn Erased + Send + Sync>, [u8]>;

src/librustc_hir/hir.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ crate use FunctionRetTy::*;
99
crate use UnsafeSource::*;
1010

1111
use rustc_data_structures::fx::FxHashSet;
12-
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
12+
use rustc_data_structures::sync::{par_for_each, Send, Sync};
1313
use rustc_errors::FatalError;
1414
use rustc_macros::HashStable_Generic;
1515
use rustc_session::node_id::NodeMap;
@@ -669,17 +669,17 @@ impl Crate<'_> {
669669
{
670670
parallel!(
671671
{
672-
par_for_each_in(&self.items, |(_, item)| {
672+
par_for_each(&self.items, |(_, item)| {
673673
visitor.visit_item(item);
674674
});
675675
},
676676
{
677-
par_for_each_in(&self.trait_items, |(_, trait_item)| {
677+
par_for_each(&self.trait_items, |(_, trait_item)| {
678678
visitor.visit_trait_item(trait_item);
679679
});
680680
},
681681
{
682-
par_for_each_in(&self.impl_items, |(_, impl_item)| {
682+
par_for_each(&self.impl_items, |(_, impl_item)| {
683683
visitor.visit_impl_item(impl_item);
684684
});
685685
}

src/librustc_interface/passes.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_builtin_macros;
2121
use rustc_codegen_ssa::back::link::emit_metadata;
2222
use rustc_codegen_utils::codegen_backend::CodegenBackend;
2323
use rustc_codegen_utils::link::filename_for_metadata;
24-
use rustc_data_structures::sync::{par_iter, Lrc, Once, ParallelIterator, WorkerLocal};
24+
use rustc_data_structures::sync::{par_for_each, Lrc, Once, WorkerLocal};
2525
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
2626
use rustc_errors::PResult;
2727
use rustc_expand::base::ExtCtxt;
@@ -786,7 +786,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
786786
sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx));
787787
},
788788
{
789-
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
789+
par_for_each(&tcx.hir().krate().modules, |(&module, _)| {
790790
let local_def_id = tcx.hir().local_def_id(module);
791791
tcx.ensure().check_mod_loops(local_def_id);
792792
tcx.ensure().check_mod_attrs(local_def_id);
@@ -811,7 +811,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
811811
},
812812
{
813813
sess.time("liveness_and_intrinsic_checking", || {
814-
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
814+
par_for_each(&tcx.hir().krate().modules, |(&module, _)| {
815815
// this must run before MIR dump, because
816816
// "not all control paths return a value" is reported here.
817817
//
@@ -879,7 +879,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
879879
},
880880
{
881881
sess.time("privacy_checking_modules", || {
882-
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
882+
par_for_each(&tcx.hir().krate().modules, |(&module, _)| {
883883
tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
884884
});
885885
});

src/librustc_lint/late.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
1818
use rustc::hir::map::Map;
1919
use rustc::ty::{self, TyCtxt};
20-
use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
20+
use rustc_data_structures::sync::{join, par_for_each};
2121
use rustc_hir as hir;
2222
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
2323
use rustc_hir::intravisit as hir_visit;
@@ -481,7 +481,7 @@ pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
481481
|| {
482482
tcx.sess.time("module_lints", || {
483483
// Run per-module lints
484-
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
484+
par_for_each(&tcx.hir().krate().modules, |(&module, _)| {
485485
tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
486486
});
487487
});

src/librustc_mir/monomorphize/collector.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ use rustc::ty::print::obsolete::DefPathBasedNames;
189189
use rustc::ty::subst::{InternalSubsts, SubstsRef};
190190
use rustc::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
191191
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
192-
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
192+
use rustc_data_structures::sync::{par_for_each, MTLock, MTRef};
193193
use rustc_hir as hir;
194194
use rustc_hir::def_id::{DefId, DefIdMap, LOCAL_CRATE};
195195
use rustc_hir::itemlikevisit::ItemLikeVisitor;
@@ -291,7 +291,7 @@ pub fn collect_crate_mono_items(
291291
let inlining_map: MTRef<'_, _> = &mut inlining_map;
292292

293293
tcx.sess.time("monomorphization_collector_graph_walk", || {
294-
par_iter(roots).for_each(|root| {
294+
par_for_each(roots, |root| {
295295
let mut recursion_depths = DefIdMap::default();
296296
collect_items_rec(tcx, root, visited, &mut recursion_depths, inlining_map);
297297
});

0 commit comments

Comments
 (0)