1+ use super :: Error ;
2+
13use rustc_data_structures:: fx:: FxHashMap ;
24use rustc_data_structures:: graph:: dominators:: { self , Dominators } ;
35use rustc_data_structures:: graph:: { self , GraphSuccessors , WithNumNodes , WithStartNode } ;
@@ -313,16 +315,28 @@ impl BasicCoverageBlockData {
313315 }
314316
315317 #[ inline( always) ]
316- pub fn set_counter ( & mut self , counter_kind : CoverageKind ) -> ExpressionOperandId {
318+ pub fn set_counter (
319+ & mut self ,
320+ counter_kind : CoverageKind ,
321+ ) -> Result < ExpressionOperandId , Error > {
317322 debug_assert ! (
323+ // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
324+ // have an expression (to be injected into an existing `BasicBlock` represented by this
325+ // `BasicCoverageBlock`).
318326 self . edge_from_bcbs. is_none( ) || counter_kind. is_expression( ) ,
319327 "attempt to add a `Counter` to a BCB target with existing incoming edge counters"
320328 ) ;
321329 let operand = counter_kind. as_operand_id ( ) ;
322- self . counter_kind
323- . replace ( counter_kind)
324- . expect_none ( "attempt to set a BasicCoverageBlock coverage counter more than once" ) ;
325- operand
330+ let expect_none = self . counter_kind . replace ( counter_kind) ;
331+ if expect_none. is_some ( ) {
332+ return Error :: from_string ( format ! (
333+ "attempt to set a BasicCoverageBlock coverage counter more than once; \
334+ {:?} already had counter {:?}",
335+ self ,
336+ expect_none. unwrap( ) ,
337+ ) ) ;
338+ }
339+ Ok ( operand)
326340 }
327341
328342 #[ inline( always) ]
@@ -340,19 +354,33 @@ impl BasicCoverageBlockData {
340354 & mut self ,
341355 from_bcb : BasicCoverageBlock ,
342356 counter_kind : CoverageKind ,
343- ) -> ExpressionOperandId {
344- debug_assert ! (
345- self . counter_kind. as_ref( ) . map_or( true , |c| c. is_expression( ) ) ,
346- "attempt to add an incoming edge counter from {:?} when the target BCB already has a \
347- `Counter`",
348- from_bcb
349- ) ;
357+ ) -> Result < ExpressionOperandId , Error > {
358+ if level_enabled ! ( tracing:: Level :: DEBUG ) {
359+ // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
360+ // have an expression (to be injected into an existing `BasicBlock` represented by this
361+ // `BasicCoverageBlock`).
362+ if !self . counter_kind . as_ref ( ) . map_or ( true , |c| c. is_expression ( ) ) {
363+ return Error :: from_string ( format ! (
364+ "attempt to add an incoming edge counter from {:?} when the target BCB already \
365+ has a `Counter`",
366+ from_bcb
367+ ) ) ;
368+ }
369+ }
350370 let operand = counter_kind. as_operand_id ( ) ;
351- self . edge_from_bcbs
371+ let expect_none = self
372+ . edge_from_bcbs
352373 . get_or_insert_with ( || FxHashMap :: default ( ) )
353- . insert ( from_bcb, counter_kind)
354- . expect_none ( "attempt to set an edge counter more than once" ) ;
355- operand
374+ . insert ( from_bcb, counter_kind) ;
375+ if expect_none. is_some ( ) {
376+ return Error :: from_string ( format ! (
377+ "attempt to set an edge counter more than once; from_bcb: \
378+ {:?} already had counter {:?}",
379+ from_bcb,
380+ expect_none. unwrap( ) ,
381+ ) ) ;
382+ }
383+ Ok ( operand)
356384 }
357385
358386 #[ inline( always) ]
@@ -383,6 +411,56 @@ impl BasicCoverageBlockData {
383411 }
384412}
385413
414+ /// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`)
415+ /// as either the successor BCB itself, if it has only one incoming edge, or the successor _plus_
416+ /// the specific branching BCB, representing the edge between the two. The latter case
417+ /// distinguishes this incoming edge from other incoming edges to the same `target_bcb`.
418+ #[ derive( Clone , Copy , PartialEq , Eq ) ]
419+ pub ( crate ) struct BcbBranch {
420+ pub edge_from_bcb : Option < BasicCoverageBlock > ,
421+ pub target_bcb : BasicCoverageBlock ,
422+ }
423+
424+ impl BcbBranch {
425+ pub fn from_to (
426+ from_bcb : BasicCoverageBlock ,
427+ to_bcb : BasicCoverageBlock ,
428+ basic_coverage_blocks : & CoverageGraph ,
429+ ) -> Self {
430+ let edge_from_bcb = if basic_coverage_blocks. predecessors [ to_bcb] . len ( ) > 1 {
431+ Some ( from_bcb)
432+ } else {
433+ None
434+ } ;
435+ Self { edge_from_bcb, target_bcb : to_bcb }
436+ }
437+
438+ pub fn counter < ' a > (
439+ & self ,
440+ basic_coverage_blocks : & ' a CoverageGraph ,
441+ ) -> Option < & ' a CoverageKind > {
442+ if let Some ( from_bcb) = self . edge_from_bcb {
443+ basic_coverage_blocks[ self . target_bcb ] . edge_counter_from ( from_bcb)
444+ } else {
445+ basic_coverage_blocks[ self . target_bcb ] . counter ( )
446+ }
447+ }
448+
449+ pub fn is_only_path_to_target ( & self ) -> bool {
450+ self . edge_from_bcb . is_none ( )
451+ }
452+ }
453+
454+ impl std:: fmt:: Debug for BcbBranch {
455+ fn fmt ( & self , fmt : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
456+ if let Some ( from_bcb) = self . edge_from_bcb {
457+ write ! ( fmt, "{:?}->{:?}" , from_bcb, self . target_bcb)
458+ } else {
459+ write ! ( fmt, "{:?}" , self . target_bcb)
460+ }
461+ }
462+ }
463+
386464fn bcb_filtered_successors < ' a , ' tcx > (
387465 body : & ' tcx & ' a mir:: Body < ' tcx > ,
388466 term_kind : & ' tcx TerminatorKind < ' tcx > ,
@@ -437,14 +515,18 @@ impl TraverseCoverageGraphWithLoops {
437515 }
438516
439517 pub fn next ( & mut self ) -> Option < BasicCoverageBlock > {
440- // Strip contexts with empty worklists from the top of the stack
441- while self . context_stack . last ( ) . map_or ( false , |context| context. worklist . is_empty ( ) ) {
442- self . context_stack . pop ( ) ;
443- }
444- // Pop the next bcb off of the current context_stack. If none, all BCBs were visited.
445- while let Some ( next_bcb) =
518+ debug ! (
519+ "TraverseCoverageGraphWithLoops::next - context_stack: {:?}" ,
520+ self . context_stack. iter( ) . rev( ) . collect:: <Vec <_>>( )
521+ ) ;
522+ while let Some ( next_bcb) = {
523+ // Strip contexts with empty worklists from the top of the stack
524+ while self . context_stack . last ( ) . map_or ( false , |context| context. worklist . is_empty ( ) ) {
525+ self . context_stack . pop ( ) ;
526+ }
527+ // Pop the next bcb off of the current context_stack. If none, all BCBs were visited.
446528 self . context_stack . last_mut ( ) . map_or ( None , |context| context. worklist . pop ( ) )
447- {
529+ } {
448530 if !self . visited . insert ( next_bcb) {
449531 debug ! ( "Already visited: {:?}" , next_bcb) ;
450532 continue ;
@@ -459,9 +541,19 @@ impl TraverseCoverageGraphWithLoops {
459541 }
460542 return Some ( next_bcb) ;
461543 }
462- debug_assert_eq ! ( self . visited. count( ) , self . visited. domain_size( ) ) ;
463544 None
464545 }
546+
547+ pub fn is_complete ( & self ) -> bool {
548+ self . visited . count ( ) == self . visited . domain_size ( )
549+ }
550+
551+ pub fn unvisited ( & self ) -> Vec < BasicCoverageBlock > {
552+ let mut unvisited_set: BitSet < BasicCoverageBlock > =
553+ BitSet :: new_filled ( self . visited . domain_size ( ) ) ;
554+ unvisited_set. subtract ( & self . visited ) ;
555+ unvisited_set. iter ( ) . collect :: < Vec < _ > > ( )
556+ }
465557}
466558
467559fn find_loop_backedges (
0 commit comments