Skip to content

Commit

Permalink
coverage: Allow make_code_region to fail gracefully
Browse files Browse the repository at this point in the history
Currently there's no way for this function to return `None`, but the next patch
will make it potentially able do so in some unknown corner-cases.

If it does fail, then skipping a span or function is better than causing an ICE
that the user might have no way to avoid without disabling coverage entirely.
  • Loading branch information
Zalathar committed Dec 17, 2023
1 parent 7f845cc commit 5db359c
Showing 1 changed file with 27 additions and 12 deletions.
39 changes: 27 additions & 12 deletions compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);

let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
if mappings.is_empty() {
return;
}

self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
function_source_hash: self.function_source_hash,
Expand Down Expand Up @@ -144,18 +147,24 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {

// Process the counters and spans associated with BCB nodes.
for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
let spans = coverage_spans.spans_for_bcb(bcb);
let has_mappings = !spans.is_empty();

// If this BCB has any coverage spans, add corresponding mappings to
// the mappings table.
if has_mappings {
let has_mappings = {
let term = counter_kind.as_term();
mappings.extend(spans.iter().map(|&span| {
let code_region = make_code_region(source_map, file_name, span, body_span);
Mapping { code_region, term }
let old_mappings_len = mappings.len();

mappings.extend(coverage_spans.spans_for_bcb(bcb).iter().filter_map(|&span| {
let Some(code_region) =
make_code_region(source_map, file_name, span, body_span)
else {
debug!(?span, "Couldn't convert span to code region");
return None;
};
Some(Mapping { code_region, term })
}));
}

mappings.len() > old_mappings_len
};

let do_inject = match counter_kind {
// Counter-increment statements always need to be injected.
Expand Down Expand Up @@ -247,13 +256,19 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
data.statements.insert(0, statement);
}

/// Convert the Span into its file name, start line and column, and end line and column
/// Convert the Span into its file name, start line and column, and end line and column.
///
/// Returns `None` if the conversion failed for some reason. There is no known example
/// of code that would cause this to happen, but it's hard to rule out entirely
/// (especially in the presence of complex macros or other expansions), and if it does
/// happen then skipping a span or function is better than an ICE that the user might
/// have no way to avoid.
fn make_code_region(
source_map: &SourceMap,
file_name: Symbol,
span: Span,
body_span: Span,
) -> CodeRegion {
) -> Option<CodeRegion> {
debug!(
"Called make_code_region(file_name={}, span={}, body_span={})",
file_name,
Expand All @@ -275,13 +290,13 @@ fn make_code_region(
start_line = source_map.doctest_offset_line(&file.name, start_line);
end_line = source_map.doctest_offset_line(&file.name, end_line);
}
CodeRegion {
Some(CodeRegion {
file_name,
start_line: start_line as u32,
start_col: start_col as u32,
end_line: end_line as u32,
end_col: end_col as u32,
}
})
}

fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
Expand Down

0 comments on commit 5db359c

Please sign in to comment.