@@ -65,6 +65,7 @@ cfg_if! {
6565 }
6666
6767 use std:: ops:: Add ;
68+ use std:: panic:: { resume_unwind, catch_unwind, AssertUnwindSafe } ;
6869
6970 #[ derive( Debug ) ]
7071 pub struct Atomic <T : Copy >( Cell <T >) ;
@@ -130,7 +131,21 @@ cfg_if! {
130131 #[ macro_export]
131132 macro_rules! parallel {
132133 ( $( $blocks: tt) , * ) => {
133- $( $blocks) * ;
134+ // We catch panics here ensuring that all the blocks execute.
135+ // This makes behavior consistent with the parallel compiler.
136+ let mut panic = None ;
137+ $(
138+ if let Err ( p) = :: std:: panic:: catch_unwind(
139+ :: std:: panic:: AssertUnwindSafe ( || $blocks)
140+ ) {
141+ if panic. is_none( ) {
142+ panic = Some ( p) ;
143+ }
144+ }
145+ ) *
146+ if let Some ( panic) = panic {
147+ :: std:: panic:: resume_unwind( panic) ;
148+ }
134149 }
135150 }
136151
@@ -140,6 +155,26 @@ cfg_if! {
140155 t. into_iter( )
141156 }
142157
158+ pub fn par_for_each_in<T : IntoIterator >(
159+ t: T ,
160+ for_each:
161+ impl Fn ( <<T as IntoIterator >:: IntoIter as Iterator >:: Item ) + Sync + Send
162+ ) {
163+ // We catch panics here ensuring that all the loop iterations execute.
164+ // This makes behavior consistent with the parallel compiler.
165+ let mut panic = None ;
166+ t. into_iter( ) . for_each( |i| {
167+ if let Err ( p) = catch_unwind( AssertUnwindSafe ( || for_each( i) ) ) {
168+ if panic. is_none( ) {
169+ panic = Some ( p) ;
170+ }
171+ }
172+ } ) ;
173+ if let Some ( panic) = panic {
174+ resume_unwind( panic) ;
175+ }
176+ }
177+
143178 pub type MetadataRef = OwningRef <Box <dyn Erased >, [ u8 ] >;
144179
145180 pub use std:: rc:: Rc as Lrc ;
@@ -278,23 +313,26 @@ cfg_if! {
278313 use std:: thread;
279314 pub use rayon:: { join, scope} ;
280315
316+ /// Runs a list of blocks in parallel. The first block is executed immediately on
317+ /// the current thread. Use that for the longest running block.
281318 #[ macro_export]
282319 macro_rules! parallel {
283- ( impl [ $( $c: tt, ) * ] [ $block: tt $( , $rest: tt) * ] ) => {
284- parallel!( impl [ $block, $( $c, ) * ] [ $( $rest) , * ] )
320+ ( impl $fblock : tt [ $( $c: tt, ) * ] [ $block: tt $( , $rest: tt) * ] ) => {
321+ parallel!( impl $fblock [ $block, $( $c, ) * ] [ $( $rest) , * ] )
285322 } ;
286- ( impl [ $( $blocks: tt, ) * ] [ ] ) => {
323+ ( impl $fblock : tt [ $( $blocks: tt, ) * ] [ ] ) => {
287324 :: rustc_data_structures:: sync:: scope( |s| {
288325 $(
289326 s. spawn( |_| $blocks) ;
290327 ) *
328+ $fblock;
291329 } )
292330 } ;
293- ( $( $blocks: tt) , * ) => {
294- // Reverse the order of the blocks since Rayon executes them in reverse order
331+ ( $fblock : tt , $ ( $blocks: tt) , * ) => {
332+ // Reverse the order of the later blocks since Rayon executes them in reverse order
295333 // when using a single thread. This ensures the execution order matches that
296334 // of a single threaded rustc
297- parallel!( impl [ ] [ $( $blocks) , * ] ) ;
335+ parallel!( impl $fblock [ ] [ $( $blocks) , * ] ) ;
298336 } ;
299337 }
300338
@@ -307,6 +345,15 @@ cfg_if! {
307345 t. into_par_iter( )
308346 }
309347
348+ pub fn par_for_each_in<T : IntoParallelIterator >(
349+ t: T ,
350+ for_each: impl Fn (
351+ <<T as IntoParallelIterator >:: Iter as ParallelIterator >:: Item
352+ ) + Sync + Send
353+ ) {
354+ t. into_par_iter( ) . for_each( for_each)
355+ }
356+
310357 pub type MetadataRef = OwningRef <Box <dyn Erased + Send + Sync >, [ u8 ] >;
311358
312359 /// This makes locks panic if they are already held.
0 commit comments