Skip to content

Commit 8ad6d8b

Browse files
committed
coverage: Split out SpanFromMir from CoverageSpan
This draws a clear distinction between the fields/methods that are needed by initial span extraction and preprocessing, and those that are needed by the main "refinement" loop.
1 parent e9d0ded commit 8ad6d8b

File tree

2 files changed

+80
-66
lines changed

2 files changed

+80
-66
lines changed

compiler/rustc_mir_transform/src/coverage/spans.rs

+4-55
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
use std::cell::OnceCell;
2-
31
use rustc_data_structures::graph::WithNumNodes;
42
use rustc_index::IndexVec;
53
use rustc_middle::mir;
6-
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
4+
use rustc_span::{BytePos, Span, DUMMY_SP};
75

8-
use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
6+
use super::graph::{BasicCoverageBlock, CoverageGraph};
97
use crate::coverage::ExtractedHirInfo;
108

119
mod from_mir;
@@ -66,8 +64,6 @@ impl CoverageSpans {
6664
#[derive(Debug, Clone)]
6765
struct CoverageSpan {
6866
span: Span,
69-
expn_span: Span,
70-
current_macro_or_none: OnceCell<Option<Symbol>>,
7167
bcb: BasicCoverageBlock,
7268
/// List of all the original spans from MIR that have been merged into this
7369
/// span. Mainly used to precisely skip over gaps when truncating a span.
@@ -76,24 +72,8 @@ struct CoverageSpan {
7672
}
7773

7874
impl CoverageSpan {
79-
pub fn for_fn_sig(fn_sig_span: Span) -> Self {
80-
Self::new(fn_sig_span, fn_sig_span, START_BCB, false)
81-
}
82-
83-
pub(super) fn new(
84-
span: Span,
85-
expn_span: Span,
86-
bcb: BasicCoverageBlock,
87-
is_closure: bool,
88-
) -> Self {
89-
Self {
90-
span,
91-
expn_span,
92-
current_macro_or_none: Default::default(),
93-
bcb,
94-
merged_spans: vec![span],
95-
is_closure,
96-
}
75+
fn new(span: Span, bcb: BasicCoverageBlock, is_closure: bool) -> Self {
76+
Self { span, bcb, merged_spans: vec![span], is_closure }
9777
}
9878

9979
pub fn merge_from(&mut self, other: &Self) {
@@ -118,37 +98,6 @@ impl CoverageSpan {
11898
pub fn is_in_same_bcb(&self, other: &Self) -> bool {
11999
self.bcb == other.bcb
120100
}
121-
122-
/// If the span is part of a macro, returns the macro name symbol.
123-
pub fn current_macro(&self) -> Option<Symbol> {
124-
self.current_macro_or_none
125-
.get_or_init(|| {
126-
if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
127-
self.expn_span.ctxt().outer_expn_data().kind
128-
{
129-
return Some(current_macro);
130-
}
131-
None
132-
})
133-
.map(|symbol| symbol)
134-
}
135-
136-
/// If the span is part of a macro, and the macro is visible (expands directly to the given
137-
/// body_span), returns the macro name symbol.
138-
pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
139-
let current_macro = self.current_macro()?;
140-
let parent_callsite = self.expn_span.parent_callsite()?;
141-
142-
// In addition to matching the context of the body span, the parent callsite
143-
// must also be the source callsite, i.e. the parent must have no parent.
144-
let is_visible_macro =
145-
parent_callsite.parent_callsite().is_none() && parent_callsite.eq_ctxt(body_span);
146-
is_visible_macro.then_some(current_macro)
147-
}
148-
149-
pub fn is_macro_expansion(&self) -> bool {
150-
self.current_macro().is_some()
151-
}
152101
}
153102

154103
/// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a

compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs

+76-11
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ use rustc_middle::mir::{
44
self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
55
TerminatorKind,
66
};
7-
use rustc_span::Span;
7+
use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
88

9-
use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
9+
use crate::coverage::graph::{
10+
BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
11+
};
1012
use crate::coverage::spans::CoverageSpan;
1113
use crate::coverage::ExtractedHirInfo;
1214

@@ -17,7 +19,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
1719
) -> Vec<CoverageSpan> {
1820
let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info;
1921

20-
let mut initial_spans = vec![CoverageSpan::for_fn_sig(fn_sig_span)];
22+
let mut initial_spans = vec![SpanFromMir::for_fn_sig(fn_sig_span)];
2123

2224
if is_async_fn {
2325
// An async function desugars into a function that returns a future,
@@ -57,7 +59,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
5759
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
5860
});
5961

60-
initial_spans
62+
initial_spans.into_iter().map(SpanFromMir::into_coverage_span).collect::<Vec<_>>()
6163
}
6264

6365
/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate
@@ -67,7 +69,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
6769
///
6870
/// (The input spans should be sorted in BCB dominator order, so that the
6971
/// retained "first" span is likely to dominate the others.)
70-
fn remove_unwanted_macro_spans(initial_spans: &mut Vec<CoverageSpan>) {
72+
fn remove_unwanted_macro_spans(initial_spans: &mut Vec<SpanFromMir>) {
7173
let mut seen_spans = FxHashSet::default();
7274
initial_spans.retain(|covspan| {
7375
// Ignore (retain) closure spans and non-macro-expansion spans.
@@ -84,7 +86,7 @@ fn remove_unwanted_macro_spans(initial_spans: &mut Vec<CoverageSpan>) {
8486
/// function body, split it into two parts. The first part covers just the
8587
/// macro name plus `!`, and the second part covers the rest of the macro
8688
/// invocation. This seems to give better results for code that uses macros.
87-
fn split_visible_macro_spans(initial_spans: &mut Vec<CoverageSpan>, hir_info: &ExtractedHirInfo) {
89+
fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>, hir_info: &ExtractedHirInfo) {
8890
let mut extra_spans = vec![];
8991

9092
initial_spans.retain(|covspan| {
@@ -105,8 +107,8 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<CoverageSpan>, hir_info: &E
105107
}
106108

107109
assert!(!covspan.is_closure);
108-
extra_spans.push(CoverageSpan::new(before, covspan.expn_span, covspan.bcb, false));
109-
extra_spans.push(CoverageSpan::new(after, covspan.expn_span, covspan.bcb, false));
110+
extra_spans.push(SpanFromMir::new(before, covspan.expn_span, covspan.bcb, false));
111+
extra_spans.push(SpanFromMir::new(after, covspan.expn_span, covspan.bcb, false));
110112
false // Discard the original covspan that we just split.
111113
});
112114

@@ -125,22 +127,22 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
125127
body_span: Span,
126128
bcb: BasicCoverageBlock,
127129
bcb_data: &'a BasicCoverageBlockData,
128-
) -> impl Iterator<Item = CoverageSpan> + Captures<'a> + Captures<'tcx> {
130+
) -> impl Iterator<Item = SpanFromMir> + Captures<'a> + Captures<'tcx> {
129131
bcb_data.basic_blocks.iter().flat_map(move |&bb| {
130132
let data = &mir_body[bb];
131133

132134
let statement_spans = data.statements.iter().filter_map(move |statement| {
133135
let expn_span = filtered_statement_span(statement)?;
134136
let span = unexpand_into_body_span(expn_span, body_span)?;
135137

136-
Some(CoverageSpan::new(span, expn_span, bcb, is_closure(statement)))
138+
Some(SpanFromMir::new(span, expn_span, bcb, is_closure(statement)))
137139
});
138140

139141
let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| {
140142
let expn_span = filtered_terminator_span(terminator)?;
141143
let span = unexpand_into_body_span(expn_span, body_span)?;
142144

143-
Some(CoverageSpan::new(span, expn_span, bcb, false))
145+
Some(SpanFromMir::new(span, expn_span, bcb, false))
144146
});
145147

146148
statement_spans.chain(terminator_span)
@@ -265,3 +267,66 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
265267
fn unexpand_into_body_span(span: Span, body_span: Span) -> Option<Span> {
266268
span.find_ancestor_inside_same_ctxt(body_span)
267269
}
270+
271+
#[derive(Debug)]
272+
struct SpanFromMir {
273+
/// A copy of `expn_span` that has been "un-expanded" back to the current
274+
/// function's `body_span`. After various intermediate processing steps,
275+
/// this span is emitted as part of the final coverage mappings.
276+
///
277+
/// With the exception of `fn_sig_span`, this should always be contained
278+
/// within `body_span`.
279+
span: Span,
280+
/// The actual span that was extracted from MIR, used to look up information
281+
/// about macro expansions.
282+
expn_span: Span,
283+
current_macro_or_none: std::cell::OnceCell<Option<Symbol>>,
284+
bcb: BasicCoverageBlock,
285+
is_closure: bool,
286+
}
287+
288+
impl SpanFromMir {
289+
fn for_fn_sig(fn_sig_span: Span) -> Self {
290+
Self::new(fn_sig_span, fn_sig_span, START_BCB, false)
291+
}
292+
293+
fn new(span: Span, expn_span: Span, bcb: BasicCoverageBlock, is_closure: bool) -> Self {
294+
Self { span, expn_span, current_macro_or_none: Default::default(), bcb, is_closure }
295+
}
296+
297+
/// If the span is part of a macro, returns the macro name symbol.
298+
fn current_macro(&self) -> Option<Symbol> {
299+
self.current_macro_or_none
300+
.get_or_init(|| {
301+
if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
302+
self.expn_span.ctxt().outer_expn_data().kind
303+
{
304+
return Some(current_macro);
305+
}
306+
None
307+
})
308+
.map(|symbol| symbol)
309+
}
310+
311+
/// If the span is part of a macro, and the macro is visible (expands directly to the given
312+
/// body_span), returns the macro name symbol.
313+
fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
314+
let current_macro = self.current_macro()?;
315+
let parent_callsite = self.expn_span.parent_callsite()?;
316+
317+
// In addition to matching the context of the body span, the parent callsite
318+
// must also be the source callsite, i.e. the parent must have no parent.
319+
let is_visible_macro =
320+
parent_callsite.parent_callsite().is_none() && parent_callsite.eq_ctxt(body_span);
321+
is_visible_macro.then_some(current_macro)
322+
}
323+
324+
fn is_macro_expansion(&self) -> bool {
325+
self.current_macro().is_some()
326+
}
327+
328+
fn into_coverage_span(self) -> CoverageSpan {
329+
let Self { span, expn_span: _, current_macro_or_none: _, bcb, is_closure } = self;
330+
CoverageSpan::new(span, bcb, is_closure)
331+
}
332+
}

0 commit comments

Comments
 (0)