Skip to content

Commit 8dddc86

Browse files
authored
Rollup merge of #93144 - wesleywiser:uninhabited_type_code_cov2, r=tmandry
Work around missing code coverage data causing llvm-cov failures If we do not add code coverage instrumentation to the `Body` of a function, then when we go to generate the function record for it, we won't write any data and this later causes llvm-cov to fail when processing data for the entire coverage report. I've identified two main cases where we do not currently add code coverage instrumentation to the `Body` of a function: 1. If the function has a single `BasicBlock` and it ends with a `TerminatorKind::Unreachable`. 2. If the function is created using a proc macro of some kind. For case 1, this is typically not important as this most often occurs as a result of function definitions that take or return uninhabited types. These kinds of functions, by definition, cannot even be called so they logically should not be counted in code coverage statistics. For case 2, I haven't looked into this very much but I've noticed while testing this patch that (other than functions which are covered by case 1) the skipped function coverage debug message is occasionally triggered in large crate graphs by functions generated from a proc macro. This may have something to do with weird spans being generated by the proc macro but this is just a guess. I think it's reasonable to land this change since currently, we fail to generate *any* results from llvm-cov when a function has no coverage instrumentation applied to it. With this change, we get coverage data for all functions other than the two cases discussed above. Fixes #93054 which occurs because of uncallable functions which shouldn't have code coverage anyway. I will open an issue for missing code coverage of proc macro generated functions and leave a link here once I have a more minimal repro. r? ``@tmandry`` cc ``@richkadel``
2 parents c8ede15 + 1a0278e commit 8dddc86

File tree

3 files changed

+70
-4
lines changed

3 files changed

+70
-4
lines changed

Diff for: compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxIndexSet;
99
use rustc_hir::def::DefKind;
1010
use rustc_hir::def_id::DefIdSet;
1111
use rustc_llvm::RustString;
12+
use rustc_middle::bug;
1213
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1314
use rustc_middle::mir::coverage::CodeRegion;
1415
use rustc_middle::ty::TyCtxt;
@@ -76,10 +77,18 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
7677
let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| {
7778
mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
7879
});
79-
debug_assert!(
80-
!coverage_mapping_buffer.is_empty(),
81-
"Every `FunctionCoverage` should have at least one counter"
82-
);
80+
81+
if coverage_mapping_buffer.is_empty() {
82+
if function_coverage.is_used() {
83+
bug!(
84+
"A used function should have had coverage mapping data but did not: {}",
85+
mangled_function_name
86+
);
87+
} else {
88+
debug!("unused function had no coverage mapping data: {}", mangled_function_name);
89+
continue;
90+
}
91+
}
8392

8493
function_data.push((mangled_function_name, source_hash, is_used, coverage_mapping_buffer));
8594
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
1| |// Regression test for #93054: Functions using uninhabited types often only have a single,
2+
2| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
3+
3| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
4+
4| |
5+
5| |// compile-flags: --edition=2021
6+
6| |
7+
7| |enum Never { }
8+
8| |
9+
9| |impl Never {
10+
10| | fn foo(self) {
11+
11| | match self { }
12+
12| | make().map(|never| match never { });
13+
13| | }
14+
14| |
15+
15| | fn bar(&self) {
16+
16| | match *self { }
17+
17| | }
18+
18| |}
19+
19| |
20+
20| 0|async fn foo2(never: Never) {
21+
21| | match never { }
22+
22| |}
23+
23| |
24+
24| 0|fn make() -> Option<Never> {
25+
25| 0| None
26+
26| 0|}
27+
27| |
28+
28| 1|fn main() { }
29+

Diff for: src/test/run-make-fulldeps/coverage/issue-93054.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Regression test for #93054: Functions using uninhabited types often only have a single,
2+
// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
3+
// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
4+
5+
// compile-flags: --edition=2021
6+
7+
enum Never { }
8+
9+
impl Never {
10+
fn foo(self) {
11+
match self { }
12+
make().map(|never| match never { });
13+
}
14+
15+
fn bar(&self) {
16+
match *self { }
17+
}
18+
}
19+
20+
async fn foo2(never: Never) {
21+
match never { }
22+
}
23+
24+
fn make() -> Option<Never> {
25+
None
26+
}
27+
28+
fn main() { }

0 commit comments

Comments
 (0)