Skip to content

Commit 5de0c5f

Browse files
Rollup merge of #79958 - richkadel:llvm-coverage-counters-2.2.0, r=tmandry
Fixes reported bugs in Rust Coverage Fixes: #79569 Fixes: #79566 Fixes: #79565 For the first issue (#79569), I got hit a `debug_assert!()` before encountering the reported error message (because I have `debug = true` enabled in my config.toml). The assertion showed me that some `SwitchInt`s can have more than one target pointing to the same `BasicBlock`. I had thought that was invalid, but since it seems to be possible, I'm allowing this now. I added a new test for this. ---- In the last two cases above, both tests (intentionally) fail to compile, but the `InstrumentCoverage` pass is invoked anyway. The MIR starts with an `Unreachable` `BasicBlock`, which I hadn't encountered before. (I had assumed the `InstrumentCoverage` pass would only be invoked with MIRs from successful compilations.) I don't have test infrastructure set up to test coverage on files that fail to compile, so I didn't add a new test. r? `@tmandry` FYI: `@wesleywiser`
2 parents bfe49a0 + 36c639a commit 5de0c5f

File tree

16 files changed

+616
-53
lines changed

16 files changed

+616
-53
lines changed

compiler/rustc_interface/src/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ fn test_debugging_options_tracking_hash() {
587587
tracked!(share_generics, Some(true));
588588
tracked!(show_span, Some(String::from("abc")));
589589
tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
590-
tracked!(symbol_mangling_version, SymbolManglingVersion::V0);
590+
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
591591
tracked!(teach, true);
592592
tracked!(thinlto, Some(true));
593593
tracked!(tune_cpu, Some(String::from("abc")));

compiler/rustc_metadata/src/creader.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -706,14 +706,21 @@ impl<'a> CrateLoader<'a> {
706706
self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
707707
}
708708

709-
fn inject_profiler_runtime(&mut self) {
709+
fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
710710
if (self.sess.opts.debugging_opts.instrument_coverage
711711
|| self.sess.opts.debugging_opts.profile
712712
|| self.sess.opts.cg.profile_generate.enabled())
713713
&& !self.sess.opts.debugging_opts.no_profiler_runtime
714714
{
715715
info!("loading profiler");
716716

717+
if self.sess.contains_name(&krate.attrs, sym::no_core) {
718+
self.sess.err(
719+
"`profiler_builtins` crate (required by compiler options) \
720+
is not compatible with crate attribute `#![no_core]`",
721+
);
722+
}
723+
717724
let name = sym::profiler_builtins;
718725
let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None);
719726
let data = self.cstore.get_crate_data(cnum);
@@ -879,7 +886,7 @@ impl<'a> CrateLoader<'a> {
879886
}
880887

881888
pub fn postprocess(&mut self, krate: &ast::Crate) {
882-
self.inject_profiler_runtime();
889+
self.inject_profiler_runtime(krate);
883890
self.inject_allocator_crate(krate);
884891
self.inject_panic_runtime(krate);
885892

compiler/rustc_metadata/src/rmeta/encoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
663663
no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
664664
panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
665665
profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
666-
symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version,
666+
symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(),
667667

668668
crate_deps,
669669
dylib_dependency_formats,

compiler/rustc_mir/src/transform/coverage/graph.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,28 @@ impl CoverageGraph {
3232

3333
// Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock
3434
// equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the
35-
// each predecessor of a BCB leader_bb should be in a unique BCB, and each successor of a
36-
// BCB last_bb should be in its own unique BCB. Therefore, collecting the BCBs using
37-
// `bb_to_bcb` should work without requiring a deduplication step.
35+
// each predecessor of a BCB leader_bb should be in a unique BCB. It is possible for a
36+
// `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so
37+
// de-duplication is required. This is done without reordering the successors.
3838

39+
let bcbs_len = bcbs.len();
40+
let mut seen = IndexVec::from_elem_n(false, bcbs_len);
3941
let successors = IndexVec::from_fn_n(
4042
|bcb| {
43+
for b in seen.iter_mut() {
44+
*b = false;
45+
}
4146
let bcb_data = &bcbs[bcb];
42-
let bcb_successors =
47+
let mut bcb_successors = Vec::new();
48+
for successor in
4349
bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind)
4450
.filter_map(|&successor_bb| bb_to_bcb[successor_bb])
45-
.collect::<Vec<_>>();
46-
debug_assert!({
47-
let mut sorted = bcb_successors.clone();
48-
sorted.sort_unstable();
49-
let initial_len = sorted.len();
50-
sorted.dedup();
51-
sorted.len() == initial_len
52-
});
51+
{
52+
if !seen[successor] {
53+
seen[successor] = true;
54+
bcb_successors.push(successor);
55+
}
56+
}
5357
bcb_successors
5458
},
5559
bcbs.len(),

compiler/rustc_mir/src/transform/coverage/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
7878
return;
7979
}
8080

81+
match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind {
82+
TerminatorKind::Unreachable => {
83+
trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`");
84+
return;
85+
}
86+
_ => {}
87+
}
88+
8189
trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());
8290
Instrumentor::new(&self.name(), tcx, mir_body).inject_counters();
8391
trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());

compiler/rustc_mir/src/transform/inline.rs

-8
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@ impl<'tcx> MirPass<'tcx> for Inline {
4141
return;
4242
}
4343

44-
if tcx.sess.opts.debugging_opts.instrument_coverage {
45-
// The current implementation of source code coverage injects code region counters
46-
// into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
47-
// based function.
48-
debug!("function inlining is disabled when compiling with `instrument_coverage`");
49-
return;
50-
}
51-
5244
if inline(tcx, body) {
5345
debug!("running simplify cfg on {:?}", body.source);
5446
CfgSimplifier::new(body).simplify();

compiler/rustc_session/src/config.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,10 @@ impl DebuggingOptions {
692692
deduplicate_diagnostics: self.deduplicate_diagnostics,
693693
}
694694
}
695+
696+
pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
697+
self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
698+
}
695699
}
696700

697701
// The type of entry function, so users can have their own entry functions
@@ -1757,7 +1761,30 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
17571761
// and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
17581762
// multiple runs, including some changes to source code; so mangled names must be consistent
17591763
// across compilations.
1760-
debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
1764+
match debugging_opts.symbol_mangling_version {
1765+
None => {
1766+
debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1767+
}
1768+
Some(SymbolManglingVersion::Legacy) => {
1769+
early_warn(
1770+
error_format,
1771+
"-Z instrument-coverage requires symbol mangling version `v0`, \
1772+
but `-Z symbol-mangling-version=legacy` was specified",
1773+
);
1774+
}
1775+
Some(SymbolManglingVersion::V0) => {}
1776+
}
1777+
1778+
if debugging_opts.mir_opt_level > 1 {
1779+
early_warn(
1780+
error_format,
1781+
&format!(
1782+
"`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \
1783+
limits the effectiveness of `-Z instrument-coverage`.",
1784+
debugging_opts.mir_opt_level,
1785+
),
1786+
);
1787+
}
17611788
}
17621789

17631790
if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
@@ -2162,7 +2189,7 @@ crate mod dep_tracking {
21622189
impl_dep_tracking_hash_via_hash!(Edition);
21632190
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
21642191
impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2165-
impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2192+
impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
21662193
impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
21672194
impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
21682195

compiler/rustc_session/src/options.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -677,12 +677,12 @@ macro_rules! options {
677677
}
678678

679679
fn parse_symbol_mangling_version(
680-
slot: &mut SymbolManglingVersion,
680+
slot: &mut Option<SymbolManglingVersion>,
681681
v: Option<&str>,
682682
) -> bool {
683683
*slot = match v {
684-
Some("legacy") => SymbolManglingVersion::Legacy,
685-
Some("v0") => SymbolManglingVersion::V0,
684+
Some("legacy") => Some(SymbolManglingVersion::Legacy),
685+
Some("v0") => Some(SymbolManglingVersion::V0),
686686
_ => return false,
687687
};
688688
true
@@ -1088,9 +1088,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
10881088
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
10891089
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
10901090
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
1091-
symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1091+
symbol_mangling_version: Option<SymbolManglingVersion> = (None,
10921092
parse_symbol_mangling_version, [TRACKED],
1093-
"which mangling version to use for symbol names"),
1093+
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
10941094
teach: bool = (false, parse_bool, [TRACKED],
10951095
"show extended diagnostic help (default: no)"),
10961096
terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],

compiler/rustc_symbol_mangling/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ fn compute_symbol_name(
245245
// 2. we favor `instantiating_crate` where possible (i.e. when `Some`)
246246
let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate);
247247
let mangling_version = if mangling_version_crate == LOCAL_CRATE {
248-
tcx.sess.opts.debugging_opts.symbol_mangling_version
248+
tcx.sess.opts.debugging_opts.get_symbol_mangling_version()
249249
} else {
250250
tcx.symbol_mangling_version(mangling_version_crate)
251251
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"data": [
3+
{
4+
"files": [
5+
{
6+
"filename": "../coverage/match_or_pattern.rs",
7+
"summary": {
8+
"functions": {
9+
"count": 1,
10+
"covered": 1,
11+
"percent": 100
12+
},
13+
"instantiations": {
14+
"count": 1,
15+
"covered": 1,
16+
"percent": 100
17+
},
18+
"lines": {
19+
"count": 37,
20+
"covered": 33,
21+
"percent": 89.1891891891892
22+
},
23+
"regions": {
24+
"count": 25,
25+
"covered": 17,
26+
"notcovered": 8,
27+
"percent": 68
28+
}
29+
}
30+
}
31+
],
32+
"totals": {
33+
"functions": {
34+
"count": 1,
35+
"covered": 1,
36+
"percent": 100
37+
},
38+
"instantiations": {
39+
"count": 1,
40+
"covered": 1,
41+
"percent": 100
42+
},
43+
"lines": {
44+
"count": 37,
45+
"covered": 33,
46+
"percent": 89.1891891891892
47+
},
48+
"regions": {
49+
"count": 25,
50+
"covered": 17,
51+
"notcovered": 8,
52+
"percent": 68
53+
}
54+
}
55+
}
56+
],
57+
"type": "llvm.coverage.json.export",
58+
"version": "2.0.1"
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
1| |#![feature(or_patterns)]
2+
2| |
3+
3| 1|fn main() {
4+
4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
5+
5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
6+
6| 1| // dependent conditions.
7+
7| 1| let is_true = std::env::args().len() == 1;
8+
8| 1|
9+
9| 1| let mut a: u8 = 0;
10+
10| 1| let mut b: u8 = 0;
11+
11| 1| if is_true {
12+
12| 1| a = 2;
13+
13| 1| b = 0;
14+
14| 1| }
15+
^0
16+
15| 1| match (a, b) {
17+
16| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`.
18+
17| | // This test confirms a fix for Issue #79569.
19+
18| 0| (0 | 1, 2 | 3) => {}
20+
19| 1| _ => {}
21+
20| | }
22+
21| 1| if is_true {
23+
22| 1| a = 0;
24+
23| 1| b = 0;
25+
24| 1| }
26+
^0
27+
25| 1| match (a, b) {
28+
26| 0| (0 | 1, 2 | 3) => {}
29+
27| 1| _ => {}
30+
28| | }
31+
29| 1| if is_true {
32+
30| 1| a = 2;
33+
31| 1| b = 2;
34+
32| 1| }
35+
^0
36+
33| 1| match (a, b) {
37+
34| 0| (0 | 1, 2 | 3) => {}
38+
35| 1| _ => {}
39+
36| | }
40+
37| 1| if is_true {
41+
38| 1| a = 0;
42+
39| 1| b = 2;
43+
40| 1| }
44+
^0
45+
41| 1| match (a, b) {
46+
42| 1| (0 | 1, 2 | 3) => {}
47+
43| 0| _ => {}
48+
44| | }
49+
45| 1|}
50+

src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt

+6-6
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,8 @@ Counter in file 0 79:14 -> 79:16, 0
2828
Counter in file 0 81:1 -> 81:2, 0
2929
Counter in file 0 91:25 -> 91:34, 0
3030
Counter in file 0 5:1 -> 5:25, #1
31-
Counter in file 0 5:25 -> 6:14, #1
32-
Counter in file 0 7:9 -> 7:10, #2
33-
Counter in file 0 9:9 -> 9:10, (#1 - #2)
34-
Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2))
3531
Counter in file 0 21:1 -> 21:23, #1
32+
Counter in file 0 17:20 -> 17:21, #1
3633
Counter in file 0 67:5 -> 67:23, #1
3734
Counter in file 0 38:1 -> 38:19, #1
3835
Counter in file 0 38:19 -> 42:12, #1
@@ -46,14 +43,18 @@ Counter in file 0 44:27 -> 44:32, #8
4643
Counter in file 0 44:36 -> 44:38, (#6 + 0)
4744
Counter in file 0 45:14 -> 45:16, #7
4845
Counter in file 0 47:1 -> 47:2, (#5 + (#6 + #7))
46+
Counter in file 0 13:20 -> 13:21, #1
4947
Counter in file 0 29:1 -> 29:22, #1
5048
Counter in file 0 93:1 -> 101:2, #1
5149
Counter in file 0 91:1 -> 91:25, #1
50+
Counter in file 0 5:25 -> 6:14, #1
51+
Counter in file 0 7:9 -> 7:10, #2
52+
Counter in file 0 9:9 -> 9:10, (#1 - #2)
53+
Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2))
5254
Counter in file 0 51:5 -> 52:18, #1
5355
Counter in file 0 53:13 -> 53:14, #2
5456
Counter in file 0 63:13 -> 63:14, (#1 - #2)
5557
Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2))
56-
Counter in file 0 17:20 -> 17:21, #1
5758
Counter in file 0 49:1 -> 68:12, #1
5859
Counter in file 0 69:9 -> 69:10, #2
5960
Counter in file 0 69:14 -> 69:27, (#1 + 0)
@@ -70,7 +71,6 @@ Counter in file 0 87:14 -> 87:16, #3
7071
Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2))))
7172
Counter in file 0 17:1 -> 17:20, #1
7273
Counter in file 0 66:5 -> 66:23, #1
73-
Counter in file 0 13:20 -> 13:21, #1
7474
Counter in file 0 17:9 -> 17:10, #1
7575
Counter in file 0 17:9 -> 17:10, #1
7676
Counter in file 0 117:17 -> 117:19, #1

0 commit comments

Comments
 (0)