1
- use super :: graph :: { BasicCoverageBlock , BasicCoverageBlockData , CoverageGraph , START_BCB } ;
1
+ use std :: cell :: OnceCell ;
2
2
3
3
use rustc_data_structures:: graph:: WithNumNodes ;
4
4
use rustc_index:: IndexVec ;
5
- use rustc_middle:: mir:: {
6
- self , AggregateKind , BasicBlock , FakeReadCause , Rvalue , Statement , StatementKind , Terminator ,
7
- TerminatorKind ,
8
- } ;
9
- use rustc_span:: source_map:: original_sp;
5
+ use rustc_middle:: mir:: { self , AggregateKind , Rvalue , Statement , StatementKind } ;
10
6
use rustc_span:: { BytePos , ExpnKind , MacroKind , Span , Symbol } ;
11
7
12
- use std:: cell:: OnceCell ;
8
+ use super :: graph:: { BasicCoverageBlock , CoverageGraph , START_BCB } ;
9
+
10
+ mod from_mir;
13
11
14
12
pub ( super ) struct CoverageSpans {
15
13
/// Map from BCBs to their list of coverage spans.
@@ -53,27 +51,13 @@ impl CoverageSpans {
53
51
}
54
52
}
55
53
56
- #[ derive( Debug , Copy , Clone ) ]
57
- pub ( super ) enum CoverageStatement {
58
- Statement ( BasicBlock , Span , usize ) ,
59
- Terminator ( BasicBlock , Span ) ,
60
- }
61
-
62
- impl CoverageStatement {
63
- pub fn span ( & self ) -> Span {
64
- match self {
65
- Self :: Statement ( _, span, _) | Self :: Terminator ( _, span) => * span,
66
- }
67
- }
68
- }
69
-
70
54
/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
71
55
/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s.
72
56
/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent
73
57
/// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the
74
- /// `CoverageStatement ` vectors, and the `Span`s to cover the extent of the combined `Span`s.
58
+ /// `merged_spans ` vectors, and the `Span`s to cover the extent of the combined `Span`s.
75
59
///
76
- /// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that
60
+ /// Note: A span merged into another CoverageSpan may come from a `BasicBlock` that
77
61
/// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches
78
62
/// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock`
79
63
/// `dominates()` the `BasicBlock`s in this `CoverageSpan`.
@@ -83,7 +67,9 @@ struct CoverageSpan {
83
67
pub expn_span : Span ,
84
68
pub current_macro_or_none : OnceCell < Option < Symbol > > ,
85
69
pub bcb : BasicCoverageBlock ,
86
- pub coverage_statements : Vec < CoverageStatement > ,
70
+ /// List of all the original spans from MIR that have been merged into this
71
+ /// span. Mainly used to precisely skip over gaps when truncating a span.
72
+ pub merged_spans : Vec < Span > ,
87
73
pub is_closure : bool ,
88
74
}
89
75
@@ -94,7 +80,7 @@ impl CoverageSpan {
94
80
expn_span : fn_sig_span,
95
81
current_macro_or_none : Default :: default ( ) ,
96
82
bcb : START_BCB ,
97
- coverage_statements : vec ! [ ] ,
83
+ merged_spans : vec ! [ ] ,
98
84
is_closure : false ,
99
85
}
100
86
}
@@ -104,8 +90,6 @@ impl CoverageSpan {
104
90
span : Span ,
105
91
expn_span : Span ,
106
92
bcb : BasicCoverageBlock ,
107
- bb : BasicBlock ,
108
- stmt_index : usize ,
109
93
) -> Self {
110
94
let is_closure = match statement. kind {
111
95
StatementKind :: Assign ( box ( _, Rvalue :: Aggregate ( box ref kind, _) ) ) => {
@@ -119,39 +103,32 @@ impl CoverageSpan {
119
103
expn_span,
120
104
current_macro_or_none : Default :: default ( ) ,
121
105
bcb,
122
- coverage_statements : vec ! [ CoverageStatement :: Statement ( bb , span, stmt_index ) ] ,
106
+ merged_spans : vec ! [ span] ,
123
107
is_closure,
124
108
}
125
109
}
126
110
127
- pub fn for_terminator (
128
- span : Span ,
129
- expn_span : Span ,
130
- bcb : BasicCoverageBlock ,
131
- bb : BasicBlock ,
132
- ) -> Self {
111
+ pub fn for_terminator ( span : Span , expn_span : Span , bcb : BasicCoverageBlock ) -> Self {
133
112
Self {
134
113
span,
135
114
expn_span,
136
115
current_macro_or_none : Default :: default ( ) ,
137
116
bcb,
138
- coverage_statements : vec ! [ CoverageStatement :: Terminator ( bb , span) ] ,
117
+ merged_spans : vec ! [ span] ,
139
118
is_closure : false ,
140
119
}
141
120
}
142
121
143
122
pub fn merge_from ( & mut self , mut other : CoverageSpan ) {
144
123
debug_assert ! ( self . is_mergeable( & other) ) ;
145
124
self . span = self . span . to ( other. span ) ;
146
- self . coverage_statements . append ( & mut other. coverage_statements ) ;
125
+ self . merged_spans . append ( & mut other. merged_spans ) ;
147
126
}
148
127
149
128
pub fn cutoff_statements_at ( & mut self , cutoff_pos : BytePos ) {
150
- self . coverage_statements . retain ( |covstmt| covstmt. span ( ) . hi ( ) <= cutoff_pos) ;
151
- if let Some ( highest_covstmt) =
152
- self . coverage_statements . iter ( ) . max_by_key ( |covstmt| covstmt. span ( ) . hi ( ) )
153
- {
154
- self . span = self . span . with_hi ( highest_covstmt. span ( ) . hi ( ) ) ;
129
+ self . merged_spans . retain ( |span| span. hi ( ) <= cutoff_pos) ;
130
+ if let Some ( max_hi) = self . merged_spans . iter ( ) . map ( |span| span. hi ( ) ) . max ( ) {
131
+ self . span = self . span . with_hi ( max_hi) ;
155
132
}
156
133
}
157
134
@@ -205,13 +182,7 @@ impl CoverageSpan {
205
182
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
206
183
/// execution
207
184
/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
208
- struct CoverageSpansGenerator < ' a , ' tcx > {
209
- /// The MIR, used to look up `BasicBlockData`.
210
- mir_body : & ' a mir:: Body < ' tcx > ,
211
-
212
- /// A `Span` covering the signature of function for the MIR.
213
- fn_sig_span : Span ,
214
-
185
+ struct CoverageSpansGenerator < ' a > {
215
186
/// A `Span` covering the function body of the MIR (typically from left curly brace to right
216
187
/// curly brace).
217
188
body_span : Span ,
@@ -221,7 +192,7 @@ struct CoverageSpansGenerator<'a, 'tcx> {
221
192
222
193
/// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative
223
194
/// dominance between the `BasicCoverageBlock`s of equal `Span`s.
224
- sorted_spans_iter : Option < std:: vec:: IntoIter < CoverageSpan > > ,
195
+ sorted_spans_iter : std:: vec:: IntoIter < CoverageSpan > ,
225
196
226
197
/// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the
227
198
/// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to
@@ -261,7 +232,7 @@ struct CoverageSpansGenerator<'a, 'tcx> {
261
232
refined_spans : Vec < CoverageSpan > ,
262
233
}
263
234
264
- impl < ' a , ' tcx > CoverageSpansGenerator < ' a , ' tcx > {
235
+ impl < ' a > CoverageSpansGenerator < ' a > {
265
236
/// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
266
237
/// counted.
267
238
///
@@ -284,17 +255,22 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
284
255
/// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
285
256
/// to be).
286
257
pub ( super ) fn generate_coverage_spans (
287
- mir_body : & ' a mir:: Body < ' tcx > ,
258
+ mir_body : & mir:: Body < ' _ > ,
288
259
fn_sig_span : Span , // Ensured to be same SourceFile and SyntaxContext as `body_span`
289
260
body_span : Span ,
290
261
basic_coverage_blocks : & ' a CoverageGraph ,
291
262
) -> Vec < CoverageSpan > {
292
- let mut coverage_spans = Self {
263
+ let sorted_spans = from_mir :: mir_to_initial_sorted_coverage_spans (
293
264
mir_body,
294
265
fn_sig_span,
295
266
body_span,
296
267
basic_coverage_blocks,
297
- sorted_spans_iter : None ,
268
+ ) ;
269
+
270
+ let coverage_spans = Self {
271
+ body_span,
272
+ basic_coverage_blocks,
273
+ sorted_spans_iter : sorted_spans. into_iter ( ) ,
298
274
refined_spans : Vec :: with_capacity ( basic_coverage_blocks. num_nodes ( ) * 2 ) ,
299
275
some_curr : None ,
300
276
curr_original_span : Span :: with_root_ctxt ( BytePos ( 0 ) , BytePos ( 0 ) ) ,
@@ -304,48 +280,9 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
304
280
pending_dups : Vec :: new ( ) ,
305
281
} ;
306
282
307
- let sorted_spans = coverage_spans. mir_to_initial_sorted_coverage_spans ( ) ;
308
-
309
- coverage_spans. sorted_spans_iter = Some ( sorted_spans. into_iter ( ) ) ;
310
-
311
283
coverage_spans. to_refined_spans ( )
312
284
}
313
285
314
- fn mir_to_initial_sorted_coverage_spans ( & self ) -> Vec < CoverageSpan > {
315
- let mut initial_spans =
316
- Vec :: < CoverageSpan > :: with_capacity ( self . mir_body . basic_blocks . len ( ) * 2 ) ;
317
- for ( bcb, bcb_data) in self . basic_coverage_blocks . iter_enumerated ( ) {
318
- initial_spans. extend ( self . bcb_to_initial_coverage_spans ( bcb, bcb_data) ) ;
319
- }
320
-
321
- if initial_spans. is_empty ( ) {
322
- // This can happen if, for example, the function is unreachable (contains only a
323
- // `BasicBlock`(s) with an `Unreachable` terminator).
324
- return initial_spans;
325
- }
326
-
327
- initial_spans. push ( CoverageSpan :: for_fn_sig ( self . fn_sig_span ) ) ;
328
-
329
- initial_spans. sort_by ( |a, b| {
330
- // First sort by span start.
331
- Ord :: cmp ( & a. span . lo ( ) , & b. span . lo ( ) )
332
- // If span starts are the same, sort by span end in reverse order.
333
- // This ensures that if spans A and B are adjacent in the list,
334
- // and they overlap but are not equal, then either:
335
- // - Span A extends further left, or
336
- // - Both have the same start and span A extends further right
337
- . then_with ( || Ord :: cmp ( & a. span . hi ( ) , & b. span . hi ( ) ) . reverse ( ) )
338
- // If both spans are equal, sort the BCBs in dominator order,
339
- // so that dominating BCBs come before other BCBs they dominate.
340
- . then_with ( || self . basic_coverage_blocks . cmp_in_dominator_order ( a. bcb , b. bcb ) )
341
- // If two spans are otherwise identical, put closure spans first,
342
- // as this seems to be what the refinement step expects.
343
- . then_with ( || Ord :: cmp ( & a. is_closure , & b. is_closure ) . reverse ( ) )
344
- } ) ;
345
-
346
- initial_spans
347
- }
348
-
349
286
/// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
350
287
/// de-duplicated `CoverageSpan`s.
351
288
fn to_refined_spans ( mut self ) -> Vec < CoverageSpan > {
@@ -485,48 +422,6 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
485
422
}
486
423
}
487
424
488
- // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
489
- // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated
490
- // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
491
- // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
492
- // `Statement`s and/or `Terminator`s.)
493
- fn bcb_to_initial_coverage_spans (
494
- & self ,
495
- bcb : BasicCoverageBlock ,
496
- bcb_data : & ' a BasicCoverageBlockData ,
497
- ) -> Vec < CoverageSpan > {
498
- bcb_data
499
- . basic_blocks
500
- . iter ( )
501
- . flat_map ( |& bb| {
502
- let data = & self . mir_body [ bb] ;
503
- data. statements
504
- . iter ( )
505
- . enumerate ( )
506
- . filter_map ( move |( index, statement) | {
507
- filtered_statement_span ( statement) . map ( |span| {
508
- CoverageSpan :: for_statement (
509
- statement,
510
- function_source_span ( span, self . body_span ) ,
511
- span,
512
- bcb,
513
- bb,
514
- index,
515
- )
516
- } )
517
- } )
518
- . chain ( filtered_terminator_span ( data. terminator ( ) ) . map ( |span| {
519
- CoverageSpan :: for_terminator (
520
- function_source_span ( span, self . body_span ) ,
521
- span,
522
- bcb,
523
- bb,
524
- )
525
- } ) )
526
- } )
527
- . collect ( )
528
- }
529
-
530
425
fn curr ( & self ) -> & CoverageSpan {
531
426
self . some_curr
532
427
. as_ref ( )
@@ -589,7 +484,7 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
589
484
self . some_prev = Some ( curr) ;
590
485
self . prev_original_span = self . curr_original_span ;
591
486
}
592
- while let Some ( curr) = self . sorted_spans_iter . as_mut ( ) . unwrap ( ) . next ( ) {
487
+ while let Some ( curr) = self . sorted_spans_iter . next ( ) {
593
488
debug ! ( "FOR curr={:?}" , curr) ;
594
489
if self . some_prev . is_some ( ) && self . prev_starts_after_next ( & curr) {
595
490
debug ! (
@@ -757,7 +652,7 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
757
652
if self . pending_dups . is_empty ( ) {
758
653
let curr_span = self . curr ( ) . span ;
759
654
self . prev_mut ( ) . cutoff_statements_at ( curr_span. lo ( ) ) ;
760
- if self . prev ( ) . coverage_statements . is_empty ( ) {
655
+ if self . prev ( ) . merged_spans . is_empty ( ) {
761
656
debug ! ( " ... no non-overlapping statements to add" ) ;
762
657
} else {
763
658
debug ! ( " ... adding modified prev={:?}" , self . prev( ) ) ;
@@ -774,104 +669,3 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
774
669
self . basic_coverage_blocks . dominates ( dom_covspan. bcb , covspan. bcb )
775
670
}
776
671
}
777
-
778
- /// If the MIR `Statement` has a span contributive to computing coverage spans,
779
- /// return it; otherwise return `None`.
780
- fn filtered_statement_span ( statement : & Statement < ' _ > ) -> Option < Span > {
781
- match statement. kind {
782
- // These statements have spans that are often outside the scope of the executed source code
783
- // for their parent `BasicBlock`.
784
- StatementKind :: StorageLive ( _)
785
- | StatementKind :: StorageDead ( _)
786
- // Coverage should not be encountered, but don't inject coverage coverage
787
- | StatementKind :: Coverage ( _)
788
- // Ignore `ConstEvalCounter`s
789
- | StatementKind :: ConstEvalCounter
790
- // Ignore `Nop`s
791
- | StatementKind :: Nop => None ,
792
-
793
- // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
794
- // statements be more consistent?
795
- //
796
- // FakeReadCause::ForGuardBinding, in this example:
797
- // match somenum {
798
- // x if x < 1 => { ... }
799
- // }...
800
- // The BasicBlock within the match arm code included one of these statements, but the span
801
- // for it covered the `1` in this source. The actual statements have nothing to do with that
802
- // source span:
803
- // FakeRead(ForGuardBinding, _4);
804
- // where `_4` is:
805
- // _4 = &_1; (at the span for the first `x`)
806
- // and `_1` is the `Place` for `somenum`.
807
- //
808
- // If and when the Issue is resolved, remove this special case match pattern:
809
- StatementKind :: FakeRead ( box ( FakeReadCause :: ForGuardBinding , _) ) => None ,
810
-
811
- // Retain spans from all other statements
812
- StatementKind :: FakeRead ( box ( _, _) ) // Not including `ForGuardBinding`
813
- | StatementKind :: Intrinsic ( ..)
814
- | StatementKind :: Assign ( _)
815
- | StatementKind :: SetDiscriminant { .. }
816
- | StatementKind :: Deinit ( ..)
817
- | StatementKind :: Retag ( _, _)
818
- | StatementKind :: PlaceMention ( ..)
819
- | StatementKind :: AscribeUserType ( _, _) => {
820
- Some ( statement. source_info . span )
821
- }
822
- }
823
- }
824
-
825
- /// If the MIR `Terminator` has a span contributive to computing coverage spans,
826
- /// return it; otherwise return `None`.
827
- fn filtered_terminator_span ( terminator : & Terminator < ' _ > ) -> Option < Span > {
828
- match terminator. kind {
829
- // These terminators have spans that don't positively contribute to computing a reasonable
830
- // span of actually executed source code. (For example, SwitchInt terminators extracted from
831
- // an `if condition { block }` has a span that includes the executed block, if true,
832
- // but for coverage, the code region executed, up to *and* through the SwitchInt,
833
- // actually stops before the if's block.)
834
- TerminatorKind :: Unreachable // Unreachable blocks are not connected to the MIR CFG
835
- | TerminatorKind :: Assert { .. }
836
- | TerminatorKind :: Drop { .. }
837
- | TerminatorKind :: SwitchInt { .. }
838
- // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
839
- | TerminatorKind :: FalseEdge { .. }
840
- | TerminatorKind :: Goto { .. } => None ,
841
-
842
- // Call `func` operand can have a more specific span when part of a chain of calls
843
- | TerminatorKind :: Call { ref func, .. } => {
844
- let mut span = terminator. source_info . span ;
845
- if let mir:: Operand :: Constant ( box constant) = func {
846
- if constant. span . lo ( ) > span. lo ( ) {
847
- span = span. with_lo ( constant. span . lo ( ) ) ;
848
- }
849
- }
850
- Some ( span)
851
- }
852
-
853
- // Retain spans from all other terminators
854
- TerminatorKind :: UnwindResume
855
- | TerminatorKind :: UnwindTerminate ( _)
856
- | TerminatorKind :: Return
857
- | TerminatorKind :: Yield { .. }
858
- | TerminatorKind :: GeneratorDrop
859
- | TerminatorKind :: FalseUnwind { .. }
860
- | TerminatorKind :: InlineAsm { .. } => {
861
- Some ( terminator. source_info . span )
862
- }
863
- }
864
- }
865
-
866
- /// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range
867
- /// within the function's body source. This span is guaranteed to be contained
868
- /// within, or equal to, the `body_span`. If the extrapolated span is not
869
- /// contained within the `body_span`, the `body_span` is returned.
870
- ///
871
- /// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
872
- /// etc.).
873
- #[ inline]
874
- fn function_source_span ( span : Span , body_span : Span ) -> Span {
875
- let original_span = original_sp ( span, body_span) . with_ctxt ( body_span. ctxt ( ) ) ;
876
- if body_span. contains ( original_span) { original_span } else { body_span }
877
- }
0 commit comments