Skip to content

Commit f7c892e

Browse files
authored
Rollup merge of #118695 - Zalathar:push-refined, r=davidtwco
coverage: Merge refined spans in a separate final pass Pulling this merge step out of `push_refined_span` and into a separate pass lets us push directly to `refined_spans` instead of calling a helper method. Because the compiler can now see partial borrows of `refined_spans`, we can remove some extra code that was jumping through hoops to satisfy the borrow checker. --- ``@rustbot`` label +A-code-coverage
2 parents 646d627 + 9a43215 commit f7c892e

File tree

1 file changed

+37
-50
lines changed
  • compiler/rustc_mir_transform/src/coverage

1 file changed

+37
-50
lines changed

compiler/rustc_mir_transform/src/coverage/spans.rs

+37-50
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ impl CoverageSpan {
8989
}
9090
}
9191

92-
pub fn merge_from(&mut self, mut other: CoverageSpan) {
93-
debug_assert!(self.is_mergeable(&other));
92+
pub fn merge_from(&mut self, other: &Self) {
93+
debug_assert!(self.is_mergeable(other));
9494
self.span = self.span.to(other.span);
95-
self.merged_spans.append(&mut other.merged_spans);
95+
self.merged_spans.extend_from_slice(&other.merged_spans);
9696
}
9797

9898
pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) {
@@ -267,15 +267,15 @@ impl<'a> CoverageSpansGenerator<'a> {
267267
if curr.is_mergeable(prev) {
268268
debug!(" same bcb (and neither is a closure), merge with prev={prev:?}");
269269
let prev = self.take_prev();
270-
self.curr_mut().merge_from(prev);
270+
self.curr_mut().merge_from(&prev);
271271
self.maybe_push_macro_name_span();
272272
// Note that curr.span may now differ from curr_original_span
273273
} else if prev.span.hi() <= curr.span.lo() {
274274
debug!(
275275
" different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}",
276276
);
277277
let prev = self.take_prev();
278-
self.push_refined_span(prev);
278+
self.refined_spans.push(prev);
279279
self.maybe_push_macro_name_span();
280280
} else if prev.is_closure {
281281
// drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
@@ -322,11 +322,10 @@ impl<'a> CoverageSpansGenerator<'a> {
322322
let prev = self.take_prev();
323323
debug!(" AT END, adding last prev={prev:?}");
324324

325-
// Take `pending_dups` so that we can drain it while calling self methods.
326-
// It is never used as a field after this point.
327-
for dup in std::mem::take(&mut self.pending_dups) {
325+
// Drain any remaining dups into the output.
326+
for dup in self.pending_dups.drain(..) {
328327
debug!(" ...adding at least one pending dup={:?}", dup);
329-
self.push_refined_span(dup);
328+
self.refined_spans.push(dup);
330329
}
331330

332331
// Async functions wrap a closure that implements the body to be executed. The enclosing
@@ -343,28 +342,27 @@ impl<'a> CoverageSpansGenerator<'a> {
343342
};
344343

345344
if !body_ends_with_closure {
346-
self.push_refined_span(prev);
345+
self.refined_spans.push(prev);
347346
}
348347

348+
// Do one last merge pass, to simplify the output.
349+
self.refined_spans.dedup_by(|b, a| {
350+
if a.is_mergeable(b) {
351+
debug!(?a, ?b, "merging list-adjacent refined spans");
352+
a.merge_from(b);
353+
true
354+
} else {
355+
false
356+
}
357+
});
358+
349359
// Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
350360
// regions for the current function leave room for the closure's own coverage regions
351361
// (injected separately, from the closure's own MIR).
352362
self.refined_spans.retain(|covspan| !covspan.is_closure);
353363
self.refined_spans
354364
}
355365

356-
fn push_refined_span(&mut self, covspan: CoverageSpan) {
357-
if let Some(last) = self.refined_spans.last_mut()
358-
&& last.is_mergeable(&covspan)
359-
{
360-
// Instead of pushing the new span, merge it with the last refined span.
361-
debug!(?last, ?covspan, "merging new refined span with last refined span");
362-
last.merge_from(covspan);
363-
} else {
364-
self.refined_spans.push(covspan);
365-
}
366-
}
367-
368366
/// If `curr` is part of a new macro expansion, carve out and push a separate
369367
/// span that ends just after the macro name and its subsequent `!`.
370368
fn maybe_push_macro_name_span(&mut self) {
@@ -397,7 +395,7 @@ impl<'a> CoverageSpansGenerator<'a> {
397395
" and curr starts a new macro expansion, so add a new span just for \
398396
the macro `{visible_macro}!`, new span={macro_name_cov:?}",
399397
);
400-
self.push_refined_span(macro_name_cov);
398+
self.refined_spans.push(macro_name_cov);
401399
}
402400

403401
fn curr(&self) -> &CoverageSpan {
@@ -454,19 +452,14 @@ impl<'a> CoverageSpansGenerator<'a> {
454452
previous iteration, or prev started a new disjoint span"
455453
);
456454
if last_dup.span.hi() <= self.curr().span.lo() {
457-
// Temporarily steal `pending_dups` into a local, so that we can
458-
// drain it while calling other self methods.
459-
let mut pending_dups = std::mem::take(&mut self.pending_dups);
460-
for dup in pending_dups.drain(..) {
455+
for dup in self.pending_dups.drain(..) {
461456
debug!(" ...adding at least one pending={:?}", dup);
462-
self.push_refined_span(dup);
457+
self.refined_spans.push(dup);
463458
}
464-
// The list of dups is now empty, but we can recycle its capacity.
465-
assert!(pending_dups.is_empty() && self.pending_dups.is_empty());
466-
self.pending_dups = pending_dups;
467459
} else {
468460
self.pending_dups.clear();
469461
}
462+
assert!(self.pending_dups.is_empty());
470463
}
471464

472465
/// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
@@ -513,22 +506,18 @@ impl<'a> CoverageSpansGenerator<'a> {
513506
let has_pre_closure_span = prev.span.lo() < right_cutoff;
514507
let has_post_closure_span = prev.span.hi() > right_cutoff;
515508

516-
// Temporarily steal `pending_dups` into a local, so that we can
517-
// mutate and/or drain it while calling other self methods.
518-
let mut pending_dups = std::mem::take(&mut self.pending_dups);
519-
520509
if has_pre_closure_span {
521510
let mut pre_closure = self.prev().clone();
522511
pre_closure.span = pre_closure.span.with_hi(left_cutoff);
523512
debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure);
524-
if !pending_dups.is_empty() {
525-
for mut dup in pending_dups.iter().cloned() {
526-
dup.span = dup.span.with_hi(left_cutoff);
527-
debug!(" ...and at least one pre_closure dup={:?}", dup);
528-
self.push_refined_span(dup);
529-
}
513+
514+
for mut dup in self.pending_dups.iter().cloned() {
515+
dup.span = dup.span.with_hi(left_cutoff);
516+
debug!(" ...and at least one pre_closure dup={:?}", dup);
517+
self.refined_spans.push(dup);
530518
}
531-
self.push_refined_span(pre_closure);
519+
520+
self.refined_spans.push(pre_closure);
532521
}
533522

534523
if has_post_closure_span {
@@ -537,19 +526,17 @@ impl<'a> CoverageSpansGenerator<'a> {
537526
// about how the `CoverageSpan`s are ordered.)
538527
self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
539528
debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev());
540-
for dup in pending_dups.iter_mut() {
529+
530+
for dup in &mut self.pending_dups {
541531
debug!(" ...and at least one overlapping dup={:?}", dup);
542532
dup.span = dup.span.with_lo(right_cutoff);
543533
}
534+
544535
let closure_covspan = self.take_curr(); // Prevent this curr from becoming prev.
545-
self.push_refined_span(closure_covspan); // since self.prev() was already updated
536+
self.refined_spans.push(closure_covspan); // since self.prev() was already updated
546537
} else {
547-
pending_dups.clear();
538+
self.pending_dups.clear();
548539
}
549-
550-
// Restore the modified post-closure spans, or the empty vector's capacity.
551-
assert!(self.pending_dups.is_empty());
552-
self.pending_dups = pending_dups;
553540
}
554541

555542
/// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
@@ -645,7 +632,7 @@ impl<'a> CoverageSpansGenerator<'a> {
645632
} else {
646633
debug!(" ... adding modified prev={:?}", self.prev());
647634
let prev = self.take_prev();
648-
self.push_refined_span(prev);
635+
self.refined_spans.push(prev);
649636
}
650637
} else {
651638
// with `pending_dups`, `prev` cannot have any statements that don't overlap

0 commit comments

Comments
 (0)