diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2273266a3ff82..3e94f1637734a 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -587,7 +587,7 @@ fn test_debugging_options_tracking_hash() { tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); - tracked!(symbol_mangling_version, SymbolManglingVersion::V0); + tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(teach, true); tracked!(thinlto, Some(true)); tracked!(tune_cpu, Some(String::from("abc"))); diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 33cbf0fb2345e..019ca5174a223 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -706,7 +706,7 @@ impl<'a> CrateLoader<'a> { self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); } - fn inject_profiler_runtime(&mut self) { + fn inject_profiler_runtime(&mut self, krate: &ast::Crate) { if (self.sess.opts.debugging_opts.instrument_coverage || self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled()) @@ -714,6 +714,13 @@ impl<'a> CrateLoader<'a> { { info!("loading profiler"); + if self.sess.contains_name(&krate.attrs, sym::no_core) { + self.sess.err( + "`profiler_builtins` crate (required by compiler options) \ + is not compatible with crate attribute `#![no_core]`", + ); + } + let name = sym::profiler_builtins; let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None); let data = self.cstore.get_crate_data(cnum); @@ -879,7 +886,7 @@ impl<'a> CrateLoader<'a> { } pub fn postprocess(&mut self, krate: &ast::Crate) { - self.inject_profiler_runtime(); + self.inject_profiler_runtime(krate); self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 46dd0df65e06f..7b67d15f64a2e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -663,7 +663,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), - symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version, + symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(), crate_deps, dylib_dependency_formats, diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs index 2408a999c05a3..b1a1bb957e79d 100644 --- a/compiler/rustc_mir/src/transform/coverage/graph.rs +++ b/compiler/rustc_mir/src/transform/coverage/graph.rs @@ -32,24 +32,28 @@ impl CoverageGraph { // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the - // each predecessor of a BCB leader_bb should be in a unique BCB, and each successor of a - // BCB last_bb should be in its own unique BCB. Therefore, collecting the BCBs using - // `bb_to_bcb` should work without requiring a deduplication step. + // each predecessor of a BCB leader_bb should be in a unique BCB. It is possible for a + // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so + // de-duplication is required. This is done without reordering the successors. + let bcbs_len = bcbs.len(); + let mut seen = IndexVec::from_elem_n(false, bcbs_len); let successors = IndexVec::from_fn_n( |bcb| { + for b in seen.iter_mut() { + *b = false; + } let bcb_data = &bcbs[bcb]; - let bcb_successors = + let mut bcb_successors = Vec::new(); + for successor in bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind) .filter_map(|&successor_bb| bb_to_bcb[successor_bb]) - .collect::>(); - debug_assert!({ - let mut sorted = bcb_successors.clone(); - sorted.sort_unstable(); - let initial_len = sorted.len(); - sorted.dedup(); - sorted.len() == initial_len - }); + { + if !seen[successor] { + seen[successor] = true; + bcb_successors.push(successor); + } + } bcb_successors }, bcbs.len(), diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index f69748db238c0..53f7c28ee35be 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -78,6 +78,14 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { return; } + match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind { + TerminatorKind::Unreachable => { + trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`"); + return; + } + _ => {} + } + trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 4eeb8969bb110..6e7575c1d71bb 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -41,14 +41,6 @@ impl<'tcx> MirPass<'tcx> for Inline { return; } - if tcx.sess.opts.debugging_opts.instrument_coverage { - // The current implementation of source code coverage injects code region counters - // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code- - // based function. - debug!("function inlining is disabled when compiling with `instrument_coverage`"); - return; - } - if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 54abb65dc3883..b77a8b631e056 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -692,6 +692,10 @@ impl DebuggingOptions { deduplicate_diagnostics: self.deduplicate_diagnostics, } } + + pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { + self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) + } } // 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 { // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over // multiple runs, including some changes to source code; so mangled names must be consistent // across compilations. - debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0; + match debugging_opts.symbol_mangling_version { + None => { + debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0); + } + Some(SymbolManglingVersion::Legacy) => { + early_warn( + error_format, + "-Z instrument-coverage requires symbol mangling version `v0`, \ + but `-Z symbol-mangling-version=legacy` was specified", + ); + } + Some(SymbolManglingVersion::V0) => {} + } + + if debugging_opts.mir_opt_level > 1 { + early_warn( + error_format, + &format!( + "`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \ + limits the effectiveness of `-Z instrument-coverage`.", + debugging_opts.mir_opt_level, + ), + ); + } } if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { @@ -2162,7 +2189,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(Edition); impl_dep_tracking_hash_via_hash!(LinkerPluginLto); impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); - impl_dep_tracking_hash_via_hash!(SymbolManglingVersion); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(TrimmedDefPaths); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 74578f2dc179f..49a7888fd6a42 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -677,12 +677,12 @@ macro_rules! options { } fn parse_symbol_mangling_version( - slot: &mut SymbolManglingVersion, + slot: &mut Option, v: Option<&str>, ) -> bool { *slot = match v { - Some("legacy") => SymbolManglingVersion::Legacy, - Some("v0") => SymbolManglingVersion::V0, + Some("legacy") => Some(SymbolManglingVersion::Legacy), + Some("v0") => Some(SymbolManglingVersion::V0), _ => return false, }; true @@ -1088,9 +1088,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), - symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy, + symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names"), + "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 10245d21b63a5..7f8cded0ac0ec 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -245,7 +245,7 @@ fn compute_symbol_name( // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); let mangling_version = if mangling_version_crate == LOCAL_CRATE { - tcx.sess.opts.debugging_opts.symbol_mangling_version + tcx.sess.opts.debugging_opts.get_symbol_mangling_version() } else { tcx.symbol_mangling_version(mangling_version_crate) }; diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 6ca5ae40707c5..98bcadd12ee24 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -118,7 +118,7 @@ LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process covera * If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`. * You can install compatible versions of these tools via `rustup`. -The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-bintools`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands! +The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands! ```shell $ rustup component add llvm-tools-preview @@ -320,8 +320,8 @@ Rust's implementation and workflow for source-based code coverage is based on th [rustc-dev-guide-how-to-build-and-run]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html [`rustfilt`]: https://crates.io/crates/rustfilt [`json5format`]: https://crates.io/crates/json5format -[`cargo-bintools`]: https://crates.io/crates/cargo-bintools +[`cargo-binutils`]: https://crates.io/crates/cargo-binutils [`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge [`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report [`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show -[source-based code coverage in Clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html \ No newline at end of file +[source-based code coverage in Clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 47847ccb5f615..1de4b0016c567 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2274,9 +2274,12 @@ function defocusSearchBar() { function implHider(addOrRemove, fullHide) { return function(n) { - var is_method = hasClass(n, "method") || fullHide; - if (is_method || hasClass(n, "type")) { - if (is_method === true) { + var shouldHide = + fullHide === true || + hasClass(n, "method") === true || + hasClass(n, "associatedconstant") === true; + if (shouldHide === true || hasClass(n, "type") === true) { + if (shouldHide === true) { if (addOrRemove) { addClass(n, "hidden-by-impl-hider"); } else { diff --git a/src/librustdoc/html/static/noscript.css b/src/librustdoc/html/static/noscript.css index 832bd9ba2d628..ffa1a7639abbb 100644 --- a/src/librustdoc/html/static/noscript.css +++ b/src/librustdoc/html/static/noscript.css @@ -1,3 +1,9 @@ +/* +This whole CSS file is used only in case rustdoc is rendered with javascript disabled. Since a lot +of content is hidden by default (depending on the settings too), we have to overwrite some of the +rules. +*/ + #main > h2 + div, #main > h2 + h3, #main > h3 + div { display: block; } @@ -13,3 +19,7 @@ #main > h2 + h3 { display: flex; } + +#main .impl-items .hidden { + display: block !important; +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 286a29edd95e7..94b6617a071af 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -117,21 +117,9 @@ fn get_args() -> Option> { .collect() } -fn stable(name: &'static str, f: F) -> RustcOptGroup -where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, -{ - RustcOptGroup::stable(name, f) -} - -fn unstable(name: &'static str, f: F) -> RustcOptGroup -where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, -{ - RustcOptGroup::unstable(name, f) -} - fn opts() -> Vec { + let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable; + let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable; vec![ stable("h", |o| o.optflag("h", "help", "show this help message")), stable("V", |o| o.optflag("V", "version", "print rustdoc's version")), diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json new file mode 100644 index 0000000000000..8559fc84aa937 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/match_or_pattern.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 37, + "covered": 33, + "percent": 89.1891891891892 + }, + "regions": { + "count": 25, + "covered": 17, + "notcovered": 8, + "percent": 68 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 37, + "covered": 33, + "percent": 89.1891891891892 + }, + "regions": { + "count": 25, + "covered": 17, + "notcovered": 8, + "percent": 68 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt new file mode 100644 index 0000000000000..a0fccb24f9980 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt @@ -0,0 +1,50 @@ + 1| |#![feature(or_patterns)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut a: u8 = 0; + 10| 1| let mut b: u8 = 0; + 11| 1| if is_true { + 12| 1| a = 2; + 13| 1| b = 0; + 14| 1| } + ^0 + 15| 1| match (a, b) { + 16| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + 17| | // This test confirms a fix for Issue #79569. + 18| 0| (0 | 1, 2 | 3) => {} + 19| 1| _ => {} + 20| | } + 21| 1| if is_true { + 22| 1| a = 0; + 23| 1| b = 0; + 24| 1| } + ^0 + 25| 1| match (a, b) { + 26| 0| (0 | 1, 2 | 3) => {} + 27| 1| _ => {} + 28| | } + 29| 1| if is_true { + 30| 1| a = 2; + 31| 1| b = 2; + 32| 1| } + ^0 + 33| 1| match (a, b) { + 34| 0| (0 | 1, 2 | 3) => {} + 35| 1| _ => {} + 36| | } + 37| 1| if is_true { + 38| 1| a = 0; + 39| 1| b = 2; + 40| 1| } + ^0 + 41| 1| match (a, b) { + 42| 1| (0 | 1, 2 | 3) => {} + 43| 0| _ => {} + 44| | } + 45| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt index ed91e8898ee98..4df0bac8c866c 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -28,11 +28,8 @@ Counter in file 0 79:14 -> 79:16, 0 Counter in file 0 81:1 -> 81:2, 0 Counter in file 0 91:25 -> 91:34, 0 Counter in file 0 5:1 -> 5:25, #1 -Counter in file 0 5:25 -> 6:14, #1 -Counter in file 0 7:9 -> 7:10, #2 -Counter in file 0 9:9 -> 9:10, (#1 - #2) -Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 21:1 -> 21:23, #1 +Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 67:5 -> 67:23, #1 Counter in file 0 38:1 -> 38:19, #1 Counter in file 0 38:19 -> 42:12, #1 @@ -46,14 +43,18 @@ Counter in file 0 44:27 -> 44:32, #8 Counter in file 0 44:36 -> 44:38, (#6 + 0) Counter in file 0 45:14 -> 45:16, #7 Counter in file 0 47:1 -> 47:2, (#5 + (#6 + #7)) +Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 29:1 -> 29:22, #1 Counter in file 0 93:1 -> 101:2, #1 Counter in file 0 91:1 -> 91:25, #1 +Counter in file 0 5:25 -> 6:14, #1 +Counter in file 0 7:9 -> 7:10, #2 +Counter in file 0 9:9 -> 9:10, (#1 - #2) +Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 51:5 -> 52:18, #1 Counter in file 0 53:13 -> 53:14, #2 Counter in file 0 63:13 -> 63:14, (#1 - #2) Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) -Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 49:1 -> 68:12, #1 Counter in file 0 69:9 -> 69:10, #2 Counter in file 0 69:14 -> 69:27, (#1 + 0) @@ -70,7 +71,6 @@ Counter in file 0 87:14 -> 87:16, #3 Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) Counter in file 0 17:1 -> 17:20, #1 Counter in file 0 66:5 -> 66:23, #1 -Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 117:17 -> 117:19, #1 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt new file mode 100644 index 0000000000000..fc12612ce7d7e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt @@ -0,0 +1,98 @@ +Counter in file 0 3:1 -> 11:15, #1 +Counter in file 0 11:16 -> 14:6, #2 +Counter in file 0 14:6 -> 14:7, (#1 - #2) +Counter in file 0 15:11 -> 15:17, (#2 + (#1 - #2)) +Counter in file 0 18:27 -> 18:29, #5 +Counter in file 0 19:14 -> 19:16, (#3 + #4) +Counter in file 0 21:8 -> 21:15, ((#3 + #4) + #5) +Counter in file 0 21:16 -> 24:6, #6 +Counter in file 0 24:6 -> 24:7, (((#3 + #4) + #5) - #6) +Counter in file 0 25:11 -> 25:17, (#6 + (((#3 + #4) + #5) - #6)) +Counter in file 0 26:27 -> 26:29, #9 +Counter in file 0 27:14 -> 27:16, (#7 + #8) +Counter in file 0 29:8 -> 29:15, ((#7 + #8) + #9) +Counter in file 0 29:16 -> 32:6, #10 +Counter in file 0 32:6 -> 32:7, (((#7 + #8) + #9) - #10) +Counter in file 0 33:11 -> 33:17, (#10 + (((#7 + #8) + #9) - #10)) +Counter in file 0 34:27 -> 34:29, #13 +Counter in file 0 35:14 -> 35:16, (#11 + #12) +Counter in file 0 37:8 -> 37:15, ((#11 + #12) + #13) +Counter in file 0 37:16 -> 40:6, #14 +Counter in file 0 40:6 -> 40:7, (((#11 + #12) + #13) - #14) +Counter in file 0 41:11 -> 41:17, (#14 + (((#11 + #12) + #13) - #14)) +Counter in file 0 42:27 -> 42:29, #17 +Counter in file 0 43:14 -> 43:16, (#15 + #16) +Counter in file 0 45:1 -> 45:2, ((#15 + #16) + #17) +Emitting segments for file: ../coverage/match_or_pattern.rs +Combined regions: + 3:1 -> 11:15 (count=1) + 11:16 -> 14:6 (count=1) + 14:6 -> 14:7 (count=0) + 15:11 -> 15:17 (count=1) + 18:27 -> 18:29 (count=0) + 19:14 -> 19:16 (count=1) + 21:8 -> 21:15 (count=1) + 21:16 -> 24:6 (count=1) + 24:6 -> 24:7 (count=0) + 25:11 -> 25:17 (count=1) + 26:27 -> 26:29 (count=0) + 27:14 -> 27:16 (count=1) + 29:8 -> 29:15 (count=1) + 29:16 -> 32:6 (count=1) + 32:6 -> 32:7 (count=0) + 33:11 -> 33:17 (count=1) + 34:27 -> 34:29 (count=0) + 35:14 -> 35:16 (count=1) + 37:8 -> 37:15 (count=1) + 37:16 -> 40:6 (count=1) + 40:6 -> 40:7 (count=0) + 41:11 -> 41:17 (count=1) + 42:27 -> 42:29 (count=1) + 43:14 -> 43:16 (count=0) + 45:1 -> 45:2 (count=1) +Segment at 3:1 (count = 1), RegionEntry +Segment at 11:15 (count = 0), Skipped +Segment at 11:16 (count = 1), RegionEntry +Segment at 14:6 (count = 0), RegionEntry +Segment at 14:7 (count = 0), Skipped +Segment at 15:11 (count = 1), RegionEntry +Segment at 15:17 (count = 0), Skipped +Segment at 18:27 (count = 0), RegionEntry +Segment at 18:29 (count = 0), Skipped +Segment at 19:14 (count = 1), RegionEntry +Segment at 19:16 (count = 0), Skipped +Segment at 21:8 (count = 1), RegionEntry +Segment at 21:15 (count = 0), Skipped +Segment at 21:16 (count = 1), RegionEntry +Segment at 24:6 (count = 0), RegionEntry +Segment at 24:7 (count = 0), Skipped +Segment at 25:11 (count = 1), RegionEntry +Segment at 25:17 (count = 0), Skipped +Segment at 26:27 (count = 0), RegionEntry +Segment at 26:29 (count = 0), Skipped +Segment at 27:14 (count = 1), RegionEntry +Segment at 27:16 (count = 0), Skipped +Segment at 29:8 (count = 1), RegionEntry +Segment at 29:15 (count = 0), Skipped +Segment at 29:16 (count = 1), RegionEntry +Segment at 32:6 (count = 0), RegionEntry +Segment at 32:7 (count = 0), Skipped +Segment at 33:11 (count = 1), RegionEntry +Segment at 33:17 (count = 0), Skipped +Segment at 34:27 (count = 0), RegionEntry +Segment at 34:29 (count = 0), Skipped +Segment at 35:14 (count = 1), RegionEntry +Segment at 35:16 (count = 0), Skipped +Segment at 37:8 (count = 1), RegionEntry +Segment at 37:15 (count = 0), Skipped +Segment at 37:16 (count = 1), RegionEntry +Segment at 40:6 (count = 0), RegionEntry +Segment at 40:7 (count = 0), Skipped +Segment at 41:11 (count = 1), RegionEntry +Segment at 41:17 (count = 0), Skipped +Segment at 42:27 (count = 1), RegionEntry +Segment at 42:29 (count = 0), Skipped +Segment at 43:14 (count = 0), RegionEntry +Segment at 43:16 (count = 0), Skipped +Segment at 45:1 (count = 1), RegionEntry +Segment at 45:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000000..133a85c83945e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,271 @@ + + + + +match_or_pattern.main - Coverage Spans + + + +
@0,1,2,3⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut a: u8 = 0; + let mut b: u8 = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + a = 2; + b = 0; + }⦉@4,6@5⦊⦉@5 + match @7⦊(a, b)⦉@7 { + // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + // This test confirms a fix for Issue #79569. + (0 | 1, 2 | 3) => @10,11⦊{}⦉@10,11 + _ => @8⦊{}⦉@8 + } + if @12⦊is_true⦉@12 @13,15⦊{ + a = 0; + b = 0; + }⦉@13,15@14⦊⦉@14 + match @16⦊(a, b)⦉@16 { + (0 | 1, 2 | 3) => @19,20⦊{}⦉@19,20 + _ => @17⦊{}⦉@17 + } + if @21⦊is_true⦉@21 @22,24⦊{ + a = 2; + b = 2; + }⦉@22,24@23⦊⦉@23 + match @25⦊(a, b)⦉@25 { + (0 | 1, 2 | 3) => @28,29⦊{}⦉@28,29 + _ => @26⦊{}⦉@26 + } + if @30⦊is_true⦉@30 @31,33⦊{ + a = 0; + b = 2; + }⦉@31,33@32⦊⦉@32 + match @34⦊(a, b)⦉@34 { + (0 | 1, 2 | 3) => @37,38⦊{}⦉@37,38 + _ => @35⦊{}⦉@35 + } +}@39⦊⦉@39
+ + diff --git a/src/test/run-make-fulldeps/coverage/match_or_pattern.rs b/src/test/run-make-fulldeps/coverage/match_or_pattern.rs new file mode 100644 index 0000000000000..4c6a8a9b7037c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/match_or_pattern.rs @@ -0,0 +1,45 @@ +#![feature(or_patterns)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut a: u8 = 0; + let mut b: u8 = 0; + if is_true { + a = 2; + b = 0; + } + match (a, b) { + // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + // This test confirms a fix for Issue #79569. + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 0; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 2; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } +} diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index ef31c72481a23..87dd19c5d4d05 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -41,7 +41,7 @@ fn arg_value<'a, T: Deref>( match arg.next().or_else(|| args.next()) { Some(v) if pred(v) => return Some(v), - _ => {}, + _ => {} } } None @@ -121,11 +121,12 @@ You can use tool lints to allow or deny lints from your code, eg.: const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; -static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = SyncLazy::new(|| { - let hook = panic::take_hook(); - panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); - hook -}); +static ICE_HOOK: SyncLazy) + Sync + Send + 'static>> = + SyncLazy::new(|| { + let hook = panic::take_hook(); + panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); + hook + }); fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace @@ -257,14 +258,17 @@ pub fn main() { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/ - let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); + let wrapper_mode = + orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); if wrapper_mode { // we still want to be able to invoke it normally though orig_args.remove(1); } - if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) { + if !wrapper_mode + && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) + { display_help(); exit(0); } @@ -285,13 +289,11 @@ pub fn main() { if clippy_enabled { args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { - if s.is_empty() { - None - } else { - Some(s.to_string()) - } - })); + args.extend( + extra_args + .split("__CLIPPY_HACKERY__") + .filter_map(|s| if s.is_empty() { None } else { Some(s.to_string()) }), + ); } } let mut clippy = ClippyCallbacks; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 057b0884e287a..952782175f13c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -214,12 +214,12 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { for (name, license) in EXCEPTIONS { // Check that the package actually exists. if !metadata.packages.iter().any(|p| p.name == *name) { - println!( + tidy_error!( + bad, "could not find exception package `{}`\n\ Remove from EXCEPTIONS list if it is no longer used.", name ); - *bad = true; } // Check that the license hasn't changed. for pkg in metadata.packages.iter().filter(|p| p.name == *name) { @@ -232,11 +232,11 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { } match &pkg.license { None => { - println!( + tidy_error!( + bad, "dependency exception `{}` does not declare a license expression", pkg.id ); - *bad = true; } Some(pkg_license) => { if pkg_license.as_str() != *license { @@ -273,8 +273,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { let license = match &pkg.license { Some(license) => license, None => { - println!("dependency `{}` does not define a license expression", pkg.id,); - *bad = true; + tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); continue; } }; @@ -286,8 +285,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) { // general, these should never be added. continue; } - println!("invalid license `{}` in `{}`", license, pkg.id); - *bad = true; + tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); } } } @@ -300,12 +298,12 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) { // Check that the PERMITTED_DEPENDENCIES does not have unused entries. for name in PERMITTED_DEPENDENCIES { if !metadata.packages.iter().any(|p| p.name == *name) { - println!( + tidy_error!( + bad, "could not find allowed package `{}`\n\ Remove from PERMITTED_DEPENDENCIES list if it is no longer used.", name ); - *bad = true; } } // Get the list in a convenient form. @@ -322,11 +320,10 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) { } if !unapproved.is_empty() { - println!("Dependencies not explicitly permitted:"); + tidy_error!(bad, "Dependencies not explicitly permitted:"); for dep in unapproved { println!("* {}", dep); } - *bad = true; } } @@ -381,16 +378,17 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect(); match matches.len() { 0 => { - println!( + tidy_error!( + bad, "crate `{}` is missing, update `check_crate_duplicate` \ if it is no longer used", name ); - *bad = true; } 1 => {} _ => { - println!( + tidy_error!( + bad, "crate `{}` is duplicated in `Cargo.lock`, \ it is too expensive to build multiple times, \ so make sure only one version appears across all dependencies", @@ -399,7 +397,6 @@ fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { for pkg in matches { println!(" * {}", pkg.id); } - *bad = true; } } } diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 93d4d3d8047d8..aad57cacbb41e 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -27,8 +27,7 @@ pub fn check(root: &Path, bad: &mut bool) { // Ensure source is allowed. if !ALLOWED_SOURCES.contains(&&*source) { - println!("invalid source: {}", source); - *bad = true; + tidy_error!(bad, "invalid source: {}", source); } } } diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 3c2880d0d5e26..d78af2cd6164c 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -330,7 +330,6 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { if level == Status::Unstable && !next_feature_omits_tracking_issue { - *bad = true; tidy_error!( bad, "{}:{}: no tracking issue for feature {}", diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index e11d293210b0a..d282d240d8234 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -28,6 +28,10 @@ macro_rules! t { } macro_rules! tidy_error { + ($bad:expr, $fmt:expr) => ({ + *$bad = true; + eprintln!("tidy error: {}", $fmt); + }); ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ *$bad = true; eprint!("tidy error: "); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 72ffdabd5222f..d8d2b449fee87 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -67,14 +67,12 @@ pub fn check(path: &Path, bad: &mut bool) { let testname = file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0; if !file_path.with_file_name(testname).with_extension("rs").exists() { - println!("Stray file with UI testing output: {:?}", file_path); - *bad = true; + tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path); } if let Ok(metadata) = fs::metadata(file_path) { if metadata.len() == 0 { - println!("Empty file with UI testing output: {:?}", file_path); - *bad = true; + tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path); } } }