Combination of commits
Fixes multiple issue with counters, with simplification Includes a change to the implicit else span in ast_lowering, so coverage of the implicit else no longer spans the `then` block. Adds coverage for unused closures and async function bodies. Fixes: #78542 Adding unreachable regions for known MIR missing from coverage map Cleaned up PR commits, and removed link-dead-code requirement and tests Coverage no longer depends on Issue #76038 (`-C link-dead-code` is no longer needed or enforced, so MSVC can use the same tests as Linux and MacOS now) Restrict adding unreachable regions to covered files Improved the code that adds coverage for uncalled functions (with MIR but not-codegenned) to avoid generating coverage in files not already included in the files with covered functions. Resolved last known issue requiring --emit llvm-ir workaround Fixed bugs in how unreachable code spans were added.
This commit is contained in:
parent
f6c9c1a576
commit
def932ca86
354 changed files with 12634 additions and 20486 deletions
|
@ -88,6 +88,7 @@ struct Instrumentor<'a, 'tcx> {
|
|||
pass_name: &'a str,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir_body: &'a mut mir::Body<'tcx>,
|
||||
fn_sig_span: Span,
|
||||
body_span: Span,
|
||||
basic_coverage_blocks: CoverageGraph,
|
||||
coverage_counters: CoverageCounters,
|
||||
|
@ -95,14 +96,19 @@ struct Instrumentor<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||
fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
|
||||
let hir_body = hir_body(tcx, mir_body.source.def_id());
|
||||
let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id());
|
||||
let body_span = hir_body.value.span;
|
||||
let fn_sig_span = match some_fn_sig {
|
||||
Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
|
||||
None => body_span.shrink_to_lo(),
|
||||
};
|
||||
let function_source_hash = hash_mir_source(tcx, hir_body);
|
||||
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
|
||||
Self {
|
||||
pass_name,
|
||||
tcx,
|
||||
mir_body,
|
||||
fn_sig_span,
|
||||
body_span,
|
||||
basic_coverage_blocks,
|
||||
coverage_counters: CoverageCounters::new(function_source_hash),
|
||||
|
@ -114,9 +120,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
|||
let source_map = tcx.sess.source_map();
|
||||
let mir_source = self.mir_body.source;
|
||||
let def_id = mir_source.def_id();
|
||||
let fn_sig_span = self.fn_sig_span;
|
||||
let body_span = self.body_span;
|
||||
|
||||
debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span));
|
||||
debug!(
|
||||
"instrumenting {:?}, fn sig span: {}, body span: {}",
|
||||
def_id,
|
||||
source_map.span_to_string(fn_sig_span),
|
||||
source_map.span_to_string(body_span)
|
||||
);
|
||||
|
||||
let mut graphviz_data = debug::GraphvizData::new();
|
||||
let mut debug_used_expressions = debug::UsedExpressions::new();
|
||||
|
@ -138,6 +150,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
|||
// Compute `CoverageSpan`s from the `CoverageGraph`.
|
||||
let coverage_spans = CoverageSpans::generate_coverage_spans(
|
||||
&self.mir_body,
|
||||
fn_sig_span,
|
||||
body_span,
|
||||
&self.basic_coverage_blocks,
|
||||
);
|
||||
|
@ -272,49 +285,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
|||
bug!("Every BasicCoverageBlock should have a Counter or Expression");
|
||||
};
|
||||
graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind);
|
||||
// FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special
|
||||
// cases?
|
||||
let some_code_region = if self.is_code_region_redundant(bcb, span, body_span) {
|
||||
None
|
||||
} else {
|
||||
Some(make_code_region(file_name, &source_file, span, body_span))
|
||||
};
|
||||
inject_statement(self.mir_body, counter_kind, self.bcb_last_bb(bcb), some_code_region);
|
||||
inject_statement(
|
||||
self.mir_body,
|
||||
counter_kind,
|
||||
self.bcb_last_bb(bcb),
|
||||
Some(make_code_region(file_name, &source_file, span, body_span)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the type of `BasicCoverageBlock` (specifically, it's `BasicBlock`s
|
||||
/// `TerminatorKind`) with the given `Span` (relative to the `body_span`) is known to produce
|
||||
/// a redundant coverage count.
|
||||
///
|
||||
/// There is at least one case for this, and if it's not handled, the last line in a function
|
||||
/// will be double-counted.
|
||||
///
|
||||
/// If this method returns `true`, the counter (which other `Expressions` may depend on) is
|
||||
/// still injected, but without an associated code region.
|
||||
// FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special cases?
|
||||
fn is_code_region_redundant(
|
||||
&self,
|
||||
bcb: BasicCoverageBlock,
|
||||
span: Span,
|
||||
body_span: Span,
|
||||
) -> bool {
|
||||
if span.hi() == body_span.hi() {
|
||||
// All functions execute a `Return`-terminated `BasicBlock`, regardless of how the
|
||||
// function returns; but only some functions also _can_ return after a `Goto` block
|
||||
// that ends on the closing brace of the function (with the `Return`). When this
|
||||
// happens, the last character is counted 2 (or possibly more) times, when we know
|
||||
// the function returned only once (of course). By giving all `Goto` terminators at
|
||||
// the end of a function a `non-reportable` code region, they are still counted
|
||||
// if appropriate, but they don't increment the line counter, as long as their is
|
||||
// also a `Return` on that last line.
|
||||
if let TerminatorKind::Goto { .. } = self.bcb_terminator(bcb).kind {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// `inject_coverage_span_counters()` looped through the `CoverageSpan`s and injected the
|
||||
/// counter from the `CoverageSpan`s `BasicCoverageBlock`, removing it from the BCB in the
|
||||
/// process (via `take_counter()`).
|
||||
|
@ -411,11 +390,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
|||
self.bcb_data(bcb).last_bb()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bcb_terminator(&self, bcb: BasicCoverageBlock) -> &Terminator<'tcx> {
|
||||
self.bcb_data(bcb).terminator(self.mir_body)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData {
|
||||
&self.basic_coverage_blocks[bcb]
|
||||
|
@ -521,10 +495,13 @@ fn make_code_region(
|
|||
}
|
||||
}
|
||||
|
||||
fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
|
||||
fn fn_sig_and_body<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) {
|
||||
let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
|
||||
let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
|
||||
tcx.hir().body(fn_body_id)
|
||||
(hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id))
|
||||
}
|
||||
|
||||
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue