Skip to content

Commit 729d7aa

Browse files
authored
Unrolled build for #148812
Rollup merge of #148812 - Zalathar:expansions, r=JonathanBrouwer coverage: Associate hole spans with expansion tree nodes This PR is another incremental step towards expansion region support in coverage instrumentation. When preparing coverage mappings for a function, we extract “raw” spans from MIR, and then use “hole” spans extracted from HIR to avoid overlap with nested items and closures. That hole-carving process was historically built around the assumption that there would be one set of spans and holes per function, but expansion region support will need to invalidate that assumption. Therefore, to be more friendly to future work on expansion regions, this PR associates each hole span with its corresponding node in the expansion tree, and makes the span refinement step obtain holes from the current node. There should be no change to compiler output.
2 parents 6d41834 + 696690b commit 729d7aa

File tree

5 files changed

+77
-62
lines changed

5 files changed

+77
-62
lines changed

compiler/rustc_mir_transform/src/coverage/expansion.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
2+
use rustc_middle::mir;
23
use rustc_middle::mir::coverage::BasicCoverageBlock;
34
use rustc_span::{ExpnId, ExpnKind, Span};
45

6+
use crate::coverage::from_mir;
7+
use crate::coverage::graph::CoverageGraph;
8+
use crate::coverage::hir_info::ExtractedHirInfo;
9+
510
#[derive(Clone, Copy, Debug)]
611
pub(crate) struct SpanWithBcb {
712
pub(crate) span: Span,
@@ -70,6 +75,10 @@ pub(crate) struct ExpnNode {
7075
pub(crate) spans: Vec<SpanWithBcb>,
7176
/// Expansions whose call-site is in this expansion.
7277
pub(crate) child_expn_ids: FxIndexSet<ExpnId>,
78+
79+
/// Hole spans belonging to this expansion, to be carved out from the
80+
/// code spans during span refinement.
81+
pub(crate) hole_spans: Vec<Span>,
7382
}
7483

7584
impl ExpnNode {
@@ -88,17 +97,27 @@ impl ExpnNode {
8897

8998
spans: vec![],
9099
child_expn_ids: FxIndexSet::default(),
100+
101+
hole_spans: vec![],
91102
}
92103
}
93104
}
94105

95-
/// Given a collection of span/BCB pairs from potentially-different syntax contexts,
106+
/// Extracts raw span/BCB pairs from potentially-different syntax contexts, and
96107
/// arranges them into an "expansion tree" based on their expansion call-sites.
97-
pub(crate) fn build_expn_tree(spans: impl IntoIterator<Item = SpanWithBcb>) -> ExpnTree {
108+
pub(crate) fn build_expn_tree(
109+
mir_body: &mir::Body<'_>,
110+
hir_info: &ExtractedHirInfo,
111+
graph: &CoverageGraph,
112+
) -> ExpnTree {
113+
let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph);
114+
98115
let mut nodes = FxIndexMap::default();
99116
let new_node = |&expn_id: &ExpnId| ExpnNode::new(expn_id);
100117

101-
for span_with_bcb in spans {
118+
for from_mir::RawSpanFromMir { raw_span, bcb } in raw_spans {
119+
let span_with_bcb = SpanWithBcb { span: raw_span, bcb };
120+
102121
// Create a node for this span's enclosing expansion, and add the span to it.
103122
let expn_id = span_with_bcb.span.ctxt().outer_expn();
104123
let node = nodes.entry(expn_id).or_insert_with_key(new_node);
@@ -123,5 +142,13 @@ pub(crate) fn build_expn_tree(spans: impl IntoIterator<Item = SpanWithBcb>) -> E
123142
}
124143
}
125144

145+
// Associate each hole span (extracted from HIR) with its corresponding
146+
// expansion tree node.
147+
for &hole_span in &hir_info.hole_spans {
148+
let expn_id = hole_span.ctxt().outer_expn();
149+
let Some(node) = nodes.get_mut(&expn_id) else { continue };
150+
node.hole_spans.push(hole_span);
151+
}
152+
126153
ExpnTree { nodes }
127154
}

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -142,19 +142,3 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
142142
| TerminatorKind::InlineAsm { .. } => Some(terminator.source_info.span),
143143
}
144144
}
145-
146-
#[derive(Debug)]
147-
pub(crate) struct Hole {
148-
pub(crate) span: Span,
149-
}
150-
151-
impl Hole {
152-
pub(crate) fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
153-
if !self.span.overlaps_or_adjacent(other.span) {
154-
return false;
155-
}
156-
157-
self.span = self.span.to(other.span);
158-
true
159-
}
160-
}

compiler/rustc_mir_transform/src/coverage/mappings.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_middle::mir::coverage::{
55
use rustc_middle::mir::{self, BasicBlock, StatementKind};
66
use rustc_middle::ty::TyCtxt;
77

8+
use crate::coverage::expansion;
89
use crate::coverage::graph::CoverageGraph;
910
use crate::coverage::hir_info::ExtractedHirInfo;
1011
use crate::coverage::spans::extract_refined_covspans;
@@ -23,10 +24,12 @@ pub(crate) fn extract_mappings_from_mir<'tcx>(
2324
hir_info: &ExtractedHirInfo,
2425
graph: &CoverageGraph,
2526
) -> ExtractedMappings {
27+
let expn_tree = expansion::build_expn_tree(mir_body, hir_info, graph);
28+
2629
let mut mappings = vec![];
2730

2831
// Extract ordinary code mappings from MIR statement/terminator spans.
29-
extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut mappings);
32+
extract_refined_covspans(tcx, hir_info, graph, &expn_tree, &mut mappings);
3033

3134
extract_branch_mappings(mir_body, hir_info, graph, &mut mappings);
3235

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::coverage::mappings::ExtractedMappings;
99

1010
mod counters;
1111
mod expansion;
12+
mod from_mir;
1213
mod graph;
1314
mod hir_info;
1415
mod mappings;

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
1-
use rustc_middle::mir;
21
use rustc_middle::mir::coverage::{Mapping, MappingKind, START_BCB};
32
use rustc_middle::ty::TyCtxt;
43
use rustc_span::source_map::SourceMap;
54
use rustc_span::{BytePos, DesugaringKind, ExpnId, ExpnKind, MacroKind, Span};
65
use tracing::instrument;
76

8-
use crate::coverage::expansion::{self, ExpnTree, SpanWithBcb};
7+
use crate::coverage::expansion::{ExpnTree, SpanWithBcb};
98
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
109
use crate::coverage::hir_info::ExtractedHirInfo;
11-
use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir};
12-
13-
mod from_mir;
1410

1511
pub(super) fn extract_refined_covspans<'tcx>(
1612
tcx: TyCtxt<'tcx>,
17-
mir_body: &mir::Body<'tcx>,
1813
hir_info: &ExtractedHirInfo,
1914
graph: &CoverageGraph,
15+
expn_tree: &ExpnTree,
2016
mappings: &mut Vec<Mapping>,
2117
) {
2218
if hir_info.is_async_fn {
@@ -32,22 +28,32 @@ pub(super) fn extract_refined_covspans<'tcx>(
3228

3329
let &ExtractedHirInfo { body_span, .. } = hir_info;
3430

35-
let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph);
36-
// Use the raw spans to build a tree of expansions for this function.
37-
let expn_tree = expansion::build_expn_tree(
38-
raw_spans
39-
.into_iter()
40-
.map(|RawSpanFromMir { raw_span, bcb }| SpanWithBcb { span: raw_span, bcb }),
41-
);
31+
// If there somehow isn't an expansion tree node corresponding to the
32+
// body span, return now and don't create any mappings.
33+
let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) else { return };
4234

4335
let mut covspans = vec![];
44-
let mut push_covspan = |covspan: Covspan| {
36+
37+
for &SpanWithBcb { span, bcb } in &node.spans {
38+
covspans.push(Covspan { span, bcb });
39+
}
40+
41+
// For each expansion with its call-site in the body span, try to
42+
// distill a corresponding covspan.
43+
for &child_expn_id in &node.child_expn_ids {
44+
if let Some(covspan) = single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id)
45+
{
46+
covspans.push(covspan);
47+
}
48+
}
49+
50+
covspans.retain(|covspan: &Covspan| {
4551
let covspan_span = covspan.span;
4652
// Discard any spans not contained within the function body span.
4753
// Also discard any spans that fill the entire body, because they tend
4854
// to represent compiler-inserted code, e.g. implicitly returning `()`.
4955
if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) {
50-
return;
56+
return false;
5157
}
5258

5359
// Each pushed covspan should have the same context as the body span.
@@ -57,27 +63,11 @@ pub(super) fn extract_refined_covspans<'tcx>(
5763
false,
5864
"span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}"
5965
);
60-
return;
66+
return false;
6167
}
6268

63-
covspans.push(covspan);
64-
};
65-
66-
if let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) {
67-
for &SpanWithBcb { span, bcb } in &node.spans {
68-
push_covspan(Covspan { span, bcb });
69-
}
70-
71-
// For each expansion with its call-site in the body span, try to
72-
// distill a corresponding covspan.
73-
for &child_expn_id in &node.child_expn_ids {
74-
if let Some(covspan) =
75-
single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id)
76-
{
77-
push_covspan(covspan);
78-
}
79-
}
80-
}
69+
true
70+
});
8171

8272
// Only proceed if we found at least one usable span.
8373
if covspans.is_empty() {
@@ -107,14 +97,8 @@ pub(super) fn extract_refined_covspans<'tcx>(
10797
covspans.dedup_by(|b, a| a.span.source_equal(b.span));
10898

10999
// Sort the holes, and merge overlapping/adjacent holes.
110-
let mut holes = hir_info
111-
.hole_spans
112-
.iter()
113-
.copied()
114-
// Discard any holes that aren't directly visible within the body span.
115-
.filter(|&hole_span| body_span.contains(hole_span) && body_span.eq_ctxt(hole_span))
116-
.map(|span| Hole { span })
117-
.collect::<Vec<_>>();
100+
let mut holes = node.hole_spans.iter().copied().map(|span| Hole { span }).collect::<Vec<_>>();
101+
118102
holes.sort_by(|a, b| compare_spans(a.span, b.span));
119103
holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b));
120104

@@ -295,3 +279,19 @@ fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
295279
})
296280
.ok()?
297281
}
282+
283+
#[derive(Debug)]
284+
struct Hole {
285+
span: Span,
286+
}
287+
288+
impl Hole {
289+
fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
290+
if !self.span.overlaps_or_adjacent(other.span) {
291+
return false;
292+
}
293+
294+
self.span = self.span.to(other.span);
295+
true
296+
}
297+
}

0 commit comments

Comments
 (0)