Skip to content

Commit 61c923b

Browse files
committed
coverage: Store fn_sig_span and body_span in the expansion tree
1 parent a3bf870 commit 61c923b

File tree

2 files changed

+49
-26
lines changed

2 files changed

+49
-26
lines changed

compiler/rustc_mir_transform/src/coverage/expansion.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ pub(crate) struct ExpnNode {
7171
/// This links an expansion node to its parent in the tree.
7272
pub(crate) call_site_expn_id: Option<ExpnId>,
7373

74+
/// Holds the function signature span, if it belongs to this expansion.
75+
/// Used by special-case code in span refinement.
76+
pub(crate) fn_sig_span: Option<Span>,
77+
/// Holds the function body span, if it belongs to this expansion.
78+
/// Used by special-case code in span refinement.
79+
pub(crate) body_span: Option<Span>,
80+
7481
/// Spans (and their associated BCBs) belonging to this expansion.
7582
pub(crate) spans: Vec<SpanWithBcb>,
7683
/// Expansions whose call-site is in this expansion.
@@ -95,6 +102,9 @@ impl ExpnNode {
95102
call_site,
96103
call_site_expn_id,
97104

105+
fn_sig_span: None,
106+
body_span: None,
107+
98108
spans: vec![],
99109
child_expn_ids: FxIndexSet::default(),
100110

@@ -142,6 +152,20 @@ pub(crate) fn build_expn_tree(
142152
}
143153
}
144154

155+
// If we have a span for the function signature, associate it with the
156+
// corresponding expansion tree node.
157+
if let Some(fn_sig_span) = hir_info.fn_sig_span
158+
&& let Some(node) = nodes.get_mut(&fn_sig_span.ctxt().outer_expn())
159+
{
160+
node.fn_sig_span = Some(fn_sig_span);
161+
}
162+
163+
// Also associate the body span with its expansion tree node.
164+
let body_span = hir_info.body_span;
165+
if let Some(node) = nodes.get_mut(&body_span.ctxt().outer_expn()) {
166+
node.body_span = Some(body_span);
167+
}
168+
145169
// Associate each hole span (extracted from HIR) with its corresponding
146170
// expansion tree node.
147171
for &hole_span in &hir_info.hole_spans {

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ pub(super) fn extract_refined_covspans<'tcx>(
2626
return;
2727
}
2828

29-
let &ExtractedHirInfo { body_span, .. } = hir_info;
30-
3129
// If there somehow isn't an expansion tree node corresponding to the
3230
// body span, return now and don't create any mappings.
33-
let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) else { return };
31+
let Some(node) = expn_tree.get(hir_info.body_span.ctxt().outer_expn()) else { return };
3432

3533
let mut covspans = vec![];
3634

@@ -47,27 +45,29 @@ pub(super) fn extract_refined_covspans<'tcx>(
4745
}
4846
}
4947

50-
covspans.retain(|covspan: &Covspan| {
51-
let covspan_span = covspan.span;
52-
// Discard any spans not contained within the function body span.
53-
// Also discard any spans that fill the entire body, because they tend
54-
// to represent compiler-inserted code, e.g. implicitly returning `()`.
55-
if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) {
56-
return false;
57-
}
48+
if let Some(body_span) = node.body_span {
49+
covspans.retain(|covspan: &Covspan| {
50+
let covspan_span = covspan.span;
51+
// Discard any spans not contained within the function body span.
52+
// Also discard any spans that fill the entire body, because they tend
53+
// to represent compiler-inserted code, e.g. implicitly returning `()`.
54+
if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) {
55+
return false;
56+
}
5857

59-
// Each pushed covspan should have the same context as the body span.
60-
// If it somehow doesn't, discard the covspan, or panic in debug builds.
61-
if !body_span.eq_ctxt(covspan_span) {
62-
debug_assert!(
63-
false,
64-
"span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}"
65-
);
66-
return false;
67-
}
58+
// Each pushed covspan should have the same context as the body span.
59+
// If it somehow doesn't, discard the covspan, or panic in debug builds.
60+
if !body_span.eq_ctxt(covspan_span) {
61+
debug_assert!(
62+
false,
63+
"span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}"
64+
);
65+
return false;
66+
}
6867

69-
true
70-
});
68+
true
69+
});
70+
}
7171

7272
// Only proceed if we found at least one usable span.
7373
if covspans.is_empty() {
@@ -78,10 +78,9 @@ pub(super) fn extract_refined_covspans<'tcx>(
7878
// Otherwise, add a fake span at the start of the body, to avoid an ugly
7979
// gap between the start of the body and the first real span.
8080
// FIXME: Find a more principled way to solve this problem.
81-
covspans.push(Covspan {
82-
span: hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()),
83-
bcb: START_BCB,
84-
});
81+
if let Some(span) = node.fn_sig_span.or_else(|| try { node.body_span?.shrink_to_lo() }) {
82+
covspans.push(Covspan { span, bcb: START_BCB });
83+
}
8584

8685
let compare_covspans = |a: &Covspan, b: &Covspan| {
8786
compare_spans(a.span, b.span)

0 commit comments

Comments
 (0)