about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2020-12-15 16:43:23 +0100
committerGitHub <noreply@github.com>2020-12-15 16:43:23 +0100
commit5de0c5f63f11e4ec283841fb98d24c00e3e02bd8 (patch)
tree6772adc1cc55027ea535f2e9e2d711d1fa655929
parentbfe49a0aa3a6cbcdbf291313e1765f5c8408b6e8 (diff)
parent36c639a2ce2808c2c95cacf0856026235ad6350f (diff)
downloadrust-5de0c5f63f11e4ec283841fb98d24c00e3e02bd8.tar.gz
rust-5de0c5f63f11e4ec283841fb98d24c00e3e02bd8.zip
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`
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_metadata/src/creader.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_mir/src/transform/coverage/graph.rs28
-rw-r--r--compiler/rustc_mir/src/transform/coverage/mod.rs8
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs8
-rw-r--r--compiler/rustc_session/src/config.rs31
-rw-r--r--compiler/rustc_session/src/options.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs2
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.match_or_pattern.json59
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt50
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt12
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.match_or_pattern.txt98
-rw-r--r--src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html271
-rw-r--r--src/test/run-make-fulldeps/coverage/match_or_pattern.rs45
-rw-r--r--src/tools/clippy/src/driver.rs32
16 files changed, 616 insertions, 53 deletions
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 2273266a3ff..3e94f163773 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 33cbf0fb234..019ca5174a2 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 46dd0df65e0..7b67d15f64a 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 2408a999c05..b1a1bb957e7 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::<Vec<_>>();
-                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 f69748db238..53f7c28ee35 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 4eeb8969bb1..6e7575c1d71 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 54abb65dc38..b77a8b631e0 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<SymbolManglingVersion>);
     impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
     impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 74578f2dc17..49a7888fd6a 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<SymbolManglingVersion>,
             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<SymbolManglingVersion> = (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<usize> = (None, parse_opt_uint, [UNTRACKED],
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 10245d21b63..7f8cded0ac0 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/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 00000000000..8559fc84aa9
--- /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 00000000000..a0fccb24f99
--- /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 ed91e8898ee..4df0bac8c86 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 00000000000..fc12612ce7d
--- /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 00000000000..133a85c8394
--- /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 @@
+<!DOCTYPE html>
+<!--
+
+Preview this file as rendered HTML from the github source at:
+https://htmlpreview.github.io/?https://github.com/rust-lang/rust/blob/master/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.match_or_pattern/match_or_pattern.main.-------.InstrumentCoverage.0.html
+
+For revisions in Pull Requests (PR):
+  * Replace "rust-lang" with the github PR author
+  * Replace "master" with the PR branch name
+
+-->
+<html>
+<head>
+<title>match_or_pattern.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)"><span class="annotation">@0,1,2,3⦊</span>fn main() {</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)">    // dependent conditions.</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)">    let is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)">    let mut a: u8 = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)">    let mut b: u8 = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb41]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb40]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:21-9:22: @3[2]: _5 = const 0_u8
+9:9-9:14: @3[3]: FakeRead(ForLet, _5)
+9:16-9:18: @3[4]: AscribeUserType(_5, o, UserTypeProjection { base: UserType(1), projs: [] })
+10:21-10:22: @3[6]: _6 = const 0_u8
+10:9-10:14: @3[7]: FakeRead(ForLet, _6)
+10:16-10:18: @3[8]: AscribeUserType(_6, o, UserTypeProjection { base: UserType(3), projs: [] })
+11:8-11:15: @3[11]: _8 = _1
+11:8-11:15: @3[12]: FakeRead(ForMatchedPlace, _8)">    if is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="12:9-12:14: @6[0]: _5 = const 2_u8
+13:9-13:14: @6[1]: _6 = const 0_u8
+11:16-14:6: @6[2]: _7 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="12:9-12:14: @6[0]: _5 = const 2_u8
+13:9-13:14: @6[1]: _6 = const 0_u8
+11:16-14:6: @6[2]: _7 = const ()">        a = 2;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="12:9-12:14: @6[0]: _5 = const 2_u8
+13:9-13:14: @6[1]: _6 = const 0_u8
+11:16-14:6: @6[2]: _7 = const ()">        b = 0;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="12:9-12:14: @6[0]: _5 = const 2_u8
+13:9-13:14: @6[1]: _6 = const 0_u8
+11:16-14:6: @6[2]: _7 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span><span class="code even" style="--layer: 1" title="14:6-14:6: @5[0]: _7 = const ()"><span class="annotation">@5⦊</span>‸<span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    match </span><span><span class="code odd" style="--layer: 1" title="15:12-15:13: @7[5]: _11 = _5
+15:15-15:16: @7[7]: _12 = _6
+15:11-15:17: @7[8]: _10 = (move _11, move _12)
+15:11-15:17: @7[11]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@7⦊</span>(a, b)<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`.</span></span>
+<span class="line"><span class="code" style="--layer: 0">        // This test confirms a fix for Issue #79569.</span></span>
+<span class="line"><span class="code" style="--layer: 0">        (0 | 1, 2 | 3) =&gt; </span><span><span class="code even" style="--layer: 1" title="18:27-18:29: @11[0]: _9 = const ()"><span class="annotation">@10,11⦊</span>{}<span class="annotation">⦉@10,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        _ =&gt; </span><span><span class="code odd" style="--layer: 1" title="19:14-19:16: @8[0]: _9 = const ()"><span class="annotation">@8⦊</span>{}<span class="annotation">⦉@8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="21:8-21:15: @12[4]: _14 = _1
+21:8-21:15: @12[5]: FakeRead(ForMatchedPlace, _14)"><span class="annotation">@12⦊</span>is_true<span class="annotation">⦉@12</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="22:9-22:14: @15[0]: _5 = const 0_u8
+23:9-23:14: @15[1]: _6 = const 0_u8
+21:16-24:6: @15[2]: _13 = const ()"><span class="annotation">@13,15⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="22:9-22:14: @15[0]: _5 = const 0_u8
+23:9-23:14: @15[1]: _6 = const 0_u8
+21:16-24:6: @15[2]: _13 = const ()">        a = 0;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="22:9-22:14: @15[0]: _5 = const 0_u8
+23:9-23:14: @15[1]: _6 = const 0_u8
+21:16-24:6: @15[2]: _13 = const ()">        b = 0;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="22:9-22:14: @15[0]: _5 = const 0_u8
+23:9-23:14: @15[1]: _6 = const 0_u8
+21:16-24:6: @15[2]: _13 = const ()">    }<span class="annotation">⦉@13,15</span></span></span><span><span class="code even" style="--layer: 1" title="24:6-24:6: @14[0]: _13 = const ()"><span class="annotation">@14⦊</span>‸<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    match </span><span><span class="code odd" style="--layer: 1" title="25:12-25:13: @16[5]: _17 = _5
+25:15-25:16: @16[7]: _18 = _6
+25:11-25:17: @16[8]: _16 = (move _17, move _18)
+25:11-25:17: @16[11]: FakeRead(ForMatchedPlace, _16)"><span class="annotation">@16⦊</span>(a, b)<span class="annotation">⦉@16</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        (0 | 1, 2 | 3) =&gt; </span><span><span class="code even" style="--layer: 1" title="26:27-26:29: @20[0]: _15 = const ()"><span class="annotation">@19,20⦊</span>{}<span class="annotation">⦉@19,20</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        _ =&gt; </span><span><span class="code odd" style="--layer: 1" title="27:14-27:16: @17[0]: _15 = const ()"><span class="annotation">@17⦊</span>{}<span class="annotation">⦉@17</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="29:8-29:15: @21[4]: _20 = _1
+29:8-29:15: @21[5]: FakeRead(ForMatchedPlace, _20)"><span class="annotation">@21⦊</span>is_true<span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="30:9-30:14: @24[0]: _5 = const 2_u8
+31:9-31:14: @24[1]: _6 = const 2_u8
+29:16-32:6: @24[2]: _19 = const ()"><span class="annotation">@22,24⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="30:9-30:14: @24[0]: _5 = const 2_u8
+31:9-31:14: @24[1]: _6 = const 2_u8
+29:16-32:6: @24[2]: _19 = const ()">        a = 2;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="30:9-30:14: @24[0]: _5 = const 2_u8
+31:9-31:14: @24[1]: _6 = const 2_u8
+29:16-32:6: @24[2]: _19 = const ()">        b = 2;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="30:9-30:14: @24[0]: _5 = const 2_u8
+31:9-31:14: @24[1]: _6 = const 2_u8
+29:16-32:6: @24[2]: _19 = const ()">    }<span class="annotation">⦉@22,24</span></span></span><span><span class="code even" style="--layer: 1" title="32:6-32:6: @23[0]: _19 = const ()"><span class="annotation">@23⦊</span>‸<span class="annotation">⦉@23</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    match </span><span><span class="code odd" style="--layer: 1" title="33:12-33:13: @25[5]: _23 = _5
+33:15-33:16: @25[7]: _24 = _6
+33:11-33:17: @25[8]: _22 = (move _23, move _24)
+33:11-33:17: @25[11]: FakeRead(ForMatchedPlace, _22)"><span class="annotation">@25⦊</span>(a, b)<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        (0 | 1, 2 | 3) =&gt; </span><span><span class="code even" style="--layer: 1" title="34:27-34:29: @29[0]: _21 = const ()"><span class="annotation">@28,29⦊</span>{}<span class="annotation">⦉@28,29</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        _ =&gt; </span><span><span class="code odd" style="--layer: 1" title="35:14-35:16: @26[0]: _21 = const ()"><span class="annotation">@26⦊</span>{}<span class="annotation">⦉@26</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="37:8-37:15: @30[4]: _26 = _1
+37:8-37:15: @30[5]: FakeRead(ForMatchedPlace, _26)"><span class="annotation">@30⦊</span>is_true<span class="annotation">⦉@30</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="38:9-38:14: @33[0]: _5 = const 0_u8
+39:9-39:14: @33[1]: _6 = const 2_u8
+37:16-40:6: @33[2]: _25 = const ()"><span class="annotation">@31,33⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="38:9-38:14: @33[0]: _5 = const 0_u8
+39:9-39:14: @33[1]: _6 = const 2_u8
+37:16-40:6: @33[2]: _25 = const ()">        a = 0;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="38:9-38:14: @33[0]: _5 = const 0_u8
+39:9-39:14: @33[1]: _6 = const 2_u8
+37:16-40:6: @33[2]: _25 = const ()">        b = 2;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="38:9-38:14: @33[0]: _5 = const 0_u8
+39:9-39:14: @33[1]: _6 = const 2_u8
+37:16-40:6: @33[2]: _25 = const ()">    }<span class="annotation">⦉@31,33</span></span></span><span><span class="code even" style="--layer: 1" title="40:6-40:6: @32[0]: _25 = const ()"><span class="annotation">@32⦊</span>‸<span class="annotation">⦉@32</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    match </span><span><span class="code odd" style="--layer: 1" title="41:12-41:13: @34[4]: _28 = _5
+41:15-41:16: @34[6]: _29 = _6
+41:11-41:17: @34[7]: _27 = (move _28, move _29)
+41:11-41:17: @34[10]: FakeRead(ForMatchedPlace, _27)"><span class="annotation">@34⦊</span>(a, b)<span class="annotation">⦉@34</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        (0 | 1, 2 | 3) =&gt; </span><span><span class="code even" style="--layer: 1" title="42:27-42:29: @38[0]: _0 = const ()"><span class="annotation">@37,38⦊</span>{}<span class="annotation">⦉@37,38</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        _ =&gt; </span><span><span class="code odd" style="--layer: 1" title="43:14-43:16: @35[0]: _0 = const ()"><span class="annotation">@35⦊</span>{}<span class="annotation">⦉@35</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="45:2-45:2: @39.Return: return"><span class="annotation">@39⦊</span>‸<span class="annotation">⦉@39</span></span></span></span></div>
+</body>
+</html>
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 00000000000..4c6a8a9b703
--- /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 ef31c72481a..87dd19c5d4d 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<Target = str>>(
 
         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<Box<dyn Fn(&panic::PanicInfo<'_>) + 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<Box<dyn Fn(&panic::PanicInfo<'_>) + 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;