@@ -126,6 +126,10 @@ struct DrainState<'cfg> {
126126    total_units :  usize , 
127127
128128    queue :  DependencyQueue < Unit ,  Artifact ,  Job > , 
129+     /// Dependency map that is like JobQueue::dep_map, except with Job information removed. 
130+      /// Used to determine if a unit's dependencies have failed, see 
131+      /// [`DrainState::spawn_work_if_possible`]. 
132+      dep_map :  HashMap < Unit ,  HashSet < ( Unit ,  Artifact ) > > , 
129133    messages :  Arc < Queue < Message > > , 
130134    /// Diagnostic deduplication support. 
131135     diag_dedupe :  DiagDedupe < ' cfg > , 
@@ -506,8 +510,15 @@ impl<'cfg> JobQueue<'cfg> {
506510        self . queue . queue_finished ( ) ; 
507511
508512        let  progress = Progress :: with_style ( "Building" ,  ProgressStyle :: Ratio ,  cx. bcx . config ) ; 
513+         let  dep_map = self 
514+             . queue 
515+             . dep_map ( ) 
516+             . iter ( ) 
517+             . map ( |( unit,  ( deps,  _) ) | ( unit. clone ( ) ,  deps. clone ( ) ) ) 
518+             . collect ( ) ; 
509519        let  state = DrainState  { 
510520            total_units :  self . queue . len ( ) , 
521+             dep_map, 
511522            queue :  self . queue , 
512523            // 100 here is somewhat arbitrary. It is a few screenfulls of 
513524            // output, and hopefully at most a few megabytes of memory for 
@@ -578,6 +589,32 @@ impl<'cfg> DrainState<'cfg> {
578589        // start requesting job tokens. Each job after the first needs to 
579590        // request a token. 
580591        while  let  Some ( ( unit,  job) )  = self . queue . dequeue ( )  { 
592+             // First, we handle the special case of fallible units. If 
593+             // this unit is allowed to fail, and any one of its dependencies 
594+             // has failed, then we should immediately mark it as failed and 
595+             // skip executing it. 
596+             if  unit. can_fail  { 
597+                 let  mut  completed_units = cx. completed_units . lock ( ) . unwrap ( ) ; 
598+                 let  failed_deps = self . dep_map [ & unit] 
599+                     . iter ( ) 
600+                     . filter ( |( dep_unit,  _) | { 
601+                         let  dep_meta = cx. files ( ) . metadata ( dep_unit) ; 
602+                         !completed_units[ & dep_meta] 
603+                     } ) 
604+                     . map ( |( _,  artifact) | artifact) 
605+                     . collect :: < HashSet < _ > > ( ) ; 
606+                 if  !failed_deps. is_empty ( )  { 
607+                     // TODO: should put a warning here saying which units were skipped 
608+                     // due to failed dependencies. 
609+                     for  artifact in  failed_deps { 
610+                         self . queue . finish ( & unit,  artifact) ; 
611+                     } 
612+                     let  unit_meta = cx. files ( ) . metadata ( & unit) ; 
613+                     completed_units. insert ( unit_meta,  false ) ; 
614+                     continue ; 
615+                 } 
616+             } 
617+ 
581618            self . pending_queue . push ( ( unit,  job) ) ; 
582619            if  self . active . len ( )  + self . pending_queue . len ( )  > 1  { 
583620                jobserver_helper. request_token ( ) ; 
@@ -713,7 +750,8 @@ impl<'cfg> DrainState<'cfg> {
713750                } ; 
714751                debug ! ( "end ({:?}): {:?}" ,  unit,  result) ; 
715752                match  result { 
716-                     Ok ( ( ) )  => self . finish ( id,  & unit,  artifact,  cx) ?, 
753+                     Ok ( ( ) )  => self . finish ( id,  & unit,  artifact,  cx,  true ) ?, 
754+                     Err ( _)  if  unit. can_fail  => self . finish ( id,  & unit,  artifact,  cx,  false ) ?, 
717755                    Err ( error)  => { 
718756                        let  msg = "The following warnings were emitted during compilation:" ; 
719757                        self . emit_warnings ( Some ( msg) ,  & unit,  cx) ?; 
@@ -1161,6 +1199,7 @@ impl<'cfg> DrainState<'cfg> {
11611199        unit :  & Unit , 
11621200        artifact :  Artifact , 
11631201        cx :  & mut  Context < ' _ ,  ' _ > , 
1202+         success :  bool , 
11641203    )  -> CargoResult < ( ) >  { 
11651204        if  unit. mode . is_run_custom_build ( )  && unit. show_warnings ( cx. bcx . config )  { 
11661205            self . emit_warnings ( None ,  unit,  cx) ?; 
@@ -1170,6 +1209,11 @@ impl<'cfg> DrainState<'cfg> {
11701209            Artifact :: All  => self . timings . unit_finished ( id,  unlocked) , 
11711210            Artifact :: Metadata  => self . timings . unit_rmeta_finished ( id,  unlocked) , 
11721211        } 
1212+         cx. completed_units 
1213+             . lock ( ) 
1214+             . unwrap ( ) 
1215+             . insert ( cx. files ( ) . metadata ( unit) ,  success) ; 
1216+ 
11731217        Ok ( ( ) ) 
11741218    } 
11751219
0 commit comments