Skip to content

Commit 439a48a

Browse files
committed
coverage: Encapsulate coverage spans
By encapsulating the coverage spans in a struct, we can change the internal representation without disturbing existing call sites. This will be useful for grouping coverage spans by BCB. This patch includes some changes that were originally in rust-lang#115912, which avoid the need for a particular test to deal with coverage spans at all.
1 parent 3d32c98 commit 439a48a

File tree

5 files changed

+67
-54
lines changed

5 files changed

+67
-54
lines changed

compiler/rustc_mir_transform/src/coverage/counters.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ use super::Error;
22

33
use super::debug;
44
use super::graph;
5-
use super::spans;
65

76
use debug::{DebugCounters, NESTED_INDENT};
87
use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops};
9-
use spans::CoverageSpan;
108

119
use rustc_data_structures::fx::FxHashMap;
1210
use rustc_data_structures::graph::WithNumNodes;
@@ -108,9 +106,9 @@ impl CoverageCounters {
108106
pub fn make_bcb_counters(
109107
&mut self,
110108
basic_coverage_blocks: &CoverageGraph,
111-
coverage_spans: &[CoverageSpan],
109+
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
112110
) -> Result<(), Error> {
113-
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(coverage_spans)
111+
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(bcb_has_coverage_spans)
114112
}
115113

116114
fn make_counter<F>(&mut self, debug_block_label_fn: F) -> BcbCounter
@@ -270,14 +268,11 @@ impl<'a> MakeBcbCounters<'a> {
270268
/// Returns any non-code-span expressions created to represent intermediate values (such as to
271269
/// add two counters so the result can be subtracted from another counter), or an Error with
272270
/// message for subsequent debugging.
273-
fn make_bcb_counters(&mut self, coverage_spans: &[CoverageSpan]) -> Result<(), Error> {
271+
fn make_bcb_counters(
272+
&mut self,
273+
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
274+
) -> Result<(), Error> {
274275
debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
275-
let num_bcbs = self.basic_coverage_blocks.num_nodes();
276-
277-
let mut bcbs_with_coverage = BitSet::new_empty(num_bcbs);
278-
for covspan in coverage_spans {
279-
bcbs_with_coverage.insert(covspan.bcb);
280-
}
281276

282277
// Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated
283278
// `CoverageSpan`, add a counter. If the `BasicCoverageBlock` branches, add a counter or
@@ -291,7 +286,7 @@ impl<'a> MakeBcbCounters<'a> {
291286
// the current BCB is in one or more nested loops or not.
292287
let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks);
293288
while let Some(bcb) = traversal.next(self.basic_coverage_blocks) {
294-
if bcbs_with_coverage.contains(bcb) {
289+
if bcb_has_coverage_spans(bcb) {
295290
debug!("{:?} has at least one `CoverageSpan`. Get or make its counter", bcb);
296291
let branching_counter_operand = self.get_or_make_counter_operand(bcb)?;
297292

compiler/rustc_mir_transform/src/coverage/debug.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ use rustc_span::Span;
124124

125125
use super::counters::{BcbCounter, CoverageCounters};
126126
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
127-
use super::spans::CoverageSpan;
127+
use super::spans::{CoverageSpan, CoverageSpans};
128128

129129
pub const NESTED_INDENT: &str = " ";
130130

@@ -614,7 +614,7 @@ pub(super) fn dump_coverage_spanview<'tcx>(
614614
basic_coverage_blocks: &CoverageGraph,
615615
pass_name: &str,
616616
body_span: Span,
617-
coverage_spans: &[CoverageSpan],
617+
coverage_spans: &CoverageSpans,
618618
) {
619619
let mir_source = mir_body.source;
620620
let def_id = mir_source.def_id();
@@ -634,10 +634,10 @@ fn span_viewables<'tcx>(
634634
tcx: TyCtxt<'tcx>,
635635
mir_body: &mir::Body<'tcx>,
636636
basic_coverage_blocks: &CoverageGraph,
637-
coverage_spans: &[CoverageSpan],
637+
coverage_spans: &CoverageSpans,
638638
) -> Vec<SpanViewable> {
639639
let mut span_viewables = Vec::new();
640-
for coverage_span in coverage_spans {
640+
for coverage_span in coverage_spans.iter() {
641641
let tooltip = coverage_span.format_coverage_statements(tcx, mir_body);
642642
let CoverageSpan { span, bcb, .. } = coverage_span;
643643
let bcb_data = &basic_coverage_blocks[*bcb];

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ mod tests;
1010

1111
use self::counters::{BcbCounter, CoverageCounters};
1212
use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
13-
use self::spans::{CoverageSpan, CoverageSpans};
13+
use self::spans::CoverageSpans;
1414

1515
use crate::MirPass;
1616

@@ -196,6 +196,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
196196
);
197197
}
198198

199+
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
200+
199201
////////////////////////////////////////////////////
200202
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
201203
// every `CoverageSpan` has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
@@ -206,7 +208,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
206208
// direct association with any `BasicCoverageBlock`, are accumulated inside `coverage_counters`.
207209
let result = self
208210
.coverage_counters
209-
.make_bcb_counters(&mut self.basic_coverage_blocks, &coverage_spans);
211+
.make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans);
210212

211213
if let Ok(()) = result {
212214
// If debugging, add any intermediate expressions (which are not associated with any
@@ -228,7 +230,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
228230
// `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph`
229231
// are indirect counters (to be injected next, without associated code regions).
230232
self.inject_coverage_span_counters(
231-
coverage_spans,
233+
&coverage_spans,
232234
&mut graphviz_data,
233235
&mut debug_used_expressions,
234236
);
@@ -290,7 +292,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
290292
/// `used_expression_operands` map.
291293
fn inject_coverage_span_counters(
292294
&mut self,
293-
coverage_spans: Vec<CoverageSpan>,
295+
coverage_spans: &CoverageSpans,
294296
graphviz_data: &mut debug::GraphvizData,
295297
debug_used_expressions: &mut debug::UsedExpressions,
296298
) {
@@ -300,7 +302,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
300302
let file_name = Symbol::intern(&self.source_file.name.prefer_remapped().to_string_lossy());
301303

302304
let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes());
303-
for covspan in coverage_spans {
305+
for covspan in coverage_spans.iter() {
304306
let bcb = covspan.bcb;
305307
let span = covspan.span;
306308
let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() {

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, ST
22

33
use itertools::Itertools;
44
use rustc_data_structures::graph::WithNumNodes;
5+
use rustc_index::bit_set::BitSet;
56
use rustc_middle::mir::spanview::source_range_no_file;
67
use rustc_middle::mir::{
78
self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
@@ -13,6 +14,42 @@ use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
1314

1415
use std::cell::OnceCell;
1516

17+
pub(super) struct CoverageSpans {
18+
coverage_spans: Vec<CoverageSpan>,
19+
bcbs_with_coverage_spans: BitSet<BasicCoverageBlock>,
20+
}
21+
22+
impl CoverageSpans {
23+
pub(super) fn generate_coverage_spans(
24+
mir_body: &mir::Body<'_>,
25+
fn_sig_span: Span,
26+
body_span: Span,
27+
basic_coverage_blocks: &CoverageGraph,
28+
) -> Self {
29+
let coverage_spans = CoverageSpansGenerator::generate_coverage_spans(
30+
mir_body,
31+
fn_sig_span,
32+
body_span,
33+
basic_coverage_blocks,
34+
);
35+
36+
let mut bcbs_with_coverage_spans = BitSet::new_empty(basic_coverage_blocks.num_nodes());
37+
for coverage_span in &coverage_spans {
38+
bcbs_with_coverage_spans.insert(coverage_span.bcb);
39+
}
40+
41+
Self { coverage_spans, bcbs_with_coverage_spans }
42+
}
43+
44+
pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
45+
self.bcbs_with_coverage_spans.contains(bcb)
46+
}
47+
48+
pub(super) fn iter(&self) -> impl Iterator<Item = &CoverageSpan> {
49+
self.coverage_spans.iter()
50+
}
51+
}
52+
1653
#[derive(Debug, Copy, Clone)]
1754
pub(super) enum CoverageStatement {
1855
Statement(BasicBlock, Span, usize),
@@ -211,7 +248,7 @@ impl CoverageSpan {
211248
/// * Merge spans that represent continuous (both in source code and control flow), non-branching
212249
/// execution
213250
/// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
214-
pub struct CoverageSpans<'a, 'tcx> {
251+
struct CoverageSpansGenerator<'a, 'tcx> {
215252
/// The MIR, used to look up `BasicBlockData`.
216253
mir_body: &'a mir::Body<'tcx>,
217254

@@ -267,7 +304,7 @@ pub struct CoverageSpans<'a, 'tcx> {
267304
refined_spans: Vec<CoverageSpan>,
268305
}
269306

270-
impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
307+
impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> {
271308
/// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
272309
/// counted.
273310
///
@@ -295,7 +332,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
295332
body_span: Span,
296333
basic_coverage_blocks: &'a CoverageGraph,
297334
) -> Vec<CoverageSpan> {
298-
let mut coverage_spans = CoverageSpans {
335+
let mut coverage_spans = Self {
299336
mir_body,
300337
fn_sig_span,
301338
body_span,
@@ -783,7 +820,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
783820

784821
/// If the MIR `Statement` has a span contributive to computing coverage spans,
785822
/// return it; otherwise return `None`.
786-
pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
823+
fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
787824
match statement.kind {
788825
// These statements have spans that are often outside the scope of the executed source code
789826
// for their parent `BasicBlock`.
@@ -830,7 +867,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
830867

831868
/// If the MIR `Terminator` has a span contributive to computing coverage spans,
832869
/// return it; otherwise return `None`.
833-
pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
870+
fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
834871
match terminator.kind {
835872
// These terminators have spans that don't positively contribute to computing a reasonable
836873
// span of actually executed source code. (For example, SwitchInt terminators extracted from
@@ -877,7 +914,7 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Sp
877914
/// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
878915
/// etc.).
879916
#[inline]
880-
pub(super) fn function_source_span(span: Span, body_span: Span) -> Span {
917+
fn function_source_span(span: Span, body_span: Span) -> Span {
881918
let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
882919
if body_span.contains(original_span) { original_span } else { body_span }
883920
}

compiler/rustc_mir_transform/src/coverage/tests.rs

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
2727
use super::counters;
2828
use super::graph;
29-
use super::spans;
29+
use super::BasicCoverageBlock;
3030

3131
use coverage_test_macros::let_bcb;
3232

@@ -644,39 +644,18 @@ fn test_traverse_coverage_with_loops() {
644644
);
645645
}
646646

647-
fn synthesize_body_span_from_terminators(mir_body: &Body<'_>) -> Span {
648-
let mut some_span: Option<Span> = None;
649-
for (_, data) in mir_body.basic_blocks.iter_enumerated() {
650-
let term_span = data.terminator().source_info.span;
651-
if let Some(span) = some_span.as_mut() {
652-
*span = span.to(term_span);
653-
} else {
654-
some_span = Some(term_span)
655-
}
656-
}
657-
some_span.expect("body must have at least one BasicBlock")
658-
}
659-
660647
#[test]
661648
fn test_make_bcb_counters() {
662649
rustc_span::create_default_session_globals_then(|| {
663650
let mir_body = goto_switchint();
664-
let body_span = synthesize_body_span_from_terminators(&mir_body);
665651
let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
666-
let mut coverage_spans = Vec::new();
667-
for (bcb, data) in basic_coverage_blocks.iter_enumerated() {
668-
if let Some(span) = spans::filtered_terminator_span(data.terminator(&mir_body)) {
669-
coverage_spans.push(spans::CoverageSpan::for_terminator(
670-
spans::function_source_span(span, body_span),
671-
span,
672-
bcb,
673-
data.last_bb(),
674-
));
675-
}
676-
}
652+
// Historically this test would use `spans` internals to set up fake
653+
// coverage spans for BCBs 1 and 2. Now we skip that step and just tell
654+
// BCB counter construction that those BCBs have spans.
655+
let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize());
677656
let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks);
678657
coverage_counters
679-
.make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans)
658+
.make_bcb_counters(&mut basic_coverage_blocks, bcb_has_coverage_spans)
680659
.expect("should be Ok");
681660
assert_eq!(coverage_counters.intermediate_expressions.len(), 0);
682661

0 commit comments

Comments
 (0)