about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-10-28 17:43:07 +0000
committerbors <bors@rust-lang.org>2023-10-28 17:43:07 +0000
commit6b78377245eae0b023fff31d15f2f8d183cfc326 (patch)
treecdc111b5604d1771b94d1f0a2cf3ee530ba55cf4
parent6a66ca215bfda3ce9c81725c7f97eeb7fcdf8c48 (diff)
parent230dd5b8c71c1d176a6705bb458a473411788f68 (diff)
downloadrust-6b78377245eae0b023fff31d15f2f8d183cfc326.tar.gz
rust-6b78377245eae0b023fff31d15f2f8d183cfc326.zip
Auto merge of #117123 - Zalathar:bad-counter-ids, r=petrochenkov
coverage: Consistently remove unused counter IDs from expressions/mappings

If some coverage counters were removed by MIR optimizations, we need to take care not to refer to those counter IDs in coverage mappings, and instead replace them with a constant zero value. If we don't, `llvm-cov` might see a too-large counter ID and silently discard the entire function from its coverage reports.

Fixes #117012.
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs72
-rw-r--r--tests/coverage-map/fn_sig_into_try.cov-map30
-rw-r--r--tests/coverage-map/status-quo/bad_counter_ids.cov-map98
-rw-r--r--tests/coverage-map/status-quo/bad_counter_ids.rs66
-rw-r--r--tests/coverage-map/status-quo/inline-dead.cov-map18
-rw-r--r--tests/coverage-map/status-quo/issue-84561.cov-map56
-rw-r--r--tests/coverage-map/status-quo/loops_branches.cov-map138
-rw-r--r--tests/coverage-map/status-quo/sort_groups.cov-map10
-rw-r--r--tests/coverage-map/status-quo/tight_inf_loop.cov-map6
-rw-r--r--tests/coverage-map/status-quo/while.cov-map10
-rw-r--r--tests/run-coverage/bad_counter_ids.coverage69
-rw-r--r--tests/run-coverage/bad_counter_ids.rs66
12 files changed, 474 insertions, 165 deletions
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 93a8a4b1d5e..cd67fafb8e4 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -102,7 +102,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
         // have zero as both of their operands, and will therefore always have
         // a value of zero. Other expressions that refer to these as operands
         // can have those operands replaced with `CovTerm::Zero`.
-        let mut zero_expressions = FxIndexSet::default();
+        let mut zero_expressions = ZeroExpressions::default();
 
         // Simplify a copy of each expression based on lower-numbered expressions,
         // and then update the set of always-zero expressions if necessary.
@@ -131,16 +131,16 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
                 )
             };
 
-            // If an operand refers to an expression that is always zero, then
-            // that operand can be replaced with `CovTerm::Zero`.
-            let maybe_set_operand_to_zero = |operand: &mut CovTerm| match *operand {
-                CovTerm::Expression(id) => {
+            // If an operand refers to a counter or expression that is always
+            // zero, then that operand can be replaced with `CovTerm::Zero`.
+            let maybe_set_operand_to_zero = |operand: &mut CovTerm| {
+                if let CovTerm::Expression(id) = *operand {
                     assert_operand_expression_is_lower(id);
-                    if zero_expressions.contains(&id) {
-                        *operand = CovTerm::Zero;
-                    }
                 }
-                _ => (),
+
+                if is_zero_term(&self.counters_seen, &zero_expressions, *operand) {
+                    *operand = CovTerm::Zero;
+                }
             };
             maybe_set_operand_to_zero(&mut lhs);
             maybe_set_operand_to_zero(&mut rhs);
@@ -159,7 +159,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
             }
         }
 
-        ZeroExpressions(zero_expressions)
+        zero_expressions
     }
 
     pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> {
@@ -205,19 +205,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
         // thing on the Rust side unless we're confident we can do much better.
         // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
 
-        let counter_from_operand = |operand: CovTerm| match operand {
-            CovTerm::Expression(id) if self.zero_expressions.contains(id) => Counter::ZERO,
-            _ => Counter::from_term(operand),
-        };
-
         self.function_coverage_info.expressions.iter().map(move |&Expression { lhs, op, rhs }| {
             CounterExpression {
-                lhs: counter_from_operand(lhs),
+                lhs: self.counter_for_term(lhs),
                 kind: match op {
                     Op::Add => ExprKind::Add,
                     Op::Subtract => ExprKind::Subtract,
                 },
-                rhs: counter_from_operand(rhs),
+                rhs: self.counter_for_term(rhs),
             }
         })
     }
@@ -227,34 +222,49 @@ impl<'tcx> FunctionCoverage<'tcx> {
     pub(crate) fn counter_regions(
         &self,
     ) -> impl Iterator<Item = (Counter, &CodeRegion)> + ExactSizeIterator {
-        // Historically, mappings were stored directly in counter/expression
-        // statements in MIR, and MIR optimizations would sometimes remove them.
-        // That's mostly no longer true, so now we detect cases where that would
-        // have happened, and zero out the corresponding mappings here instead.
-        let counter_for_term = move |term: CovTerm| {
-            let force_to_zero = match term {
-                CovTerm::Counter(id) => !self.counters_seen.contains(id),
-                CovTerm::Expression(id) => self.zero_expressions.contains(id),
-                CovTerm::Zero => false,
-            };
-            if force_to_zero { Counter::ZERO } else { Counter::from_term(term) }
-        };
-
         self.function_coverage_info.mappings.iter().map(move |mapping| {
             let &Mapping { term, ref code_region } = mapping;
-            let counter = counter_for_term(term);
+            let counter = self.counter_for_term(term);
             (counter, code_region)
         })
     }
+
+    fn counter_for_term(&self, term: CovTerm) -> Counter {
+        if is_zero_term(&self.counters_seen, &self.zero_expressions, term) {
+            Counter::ZERO
+        } else {
+            Counter::from_term(term)
+        }
+    }
 }
 
 /// Set of expression IDs that are known to always evaluate to zero.
 /// Any mapping or expression operand that refers to these expressions can have
 /// that reference replaced with a constant zero value.
+#[derive(Default)]
 struct ZeroExpressions(FxIndexSet<ExpressionId>);
 
 impl ZeroExpressions {
+    fn insert(&mut self, id: ExpressionId) {
+        self.0.insert(id);
+    }
+
     fn contains(&self, id: ExpressionId) -> bool {
         self.0.contains(&id)
     }
 }
+
+/// Returns `true` if the given term is known to have a value of zero, taking
+/// into account knowledge of which counters are unused and which expressions
+/// are always zero.
+fn is_zero_term(
+    counters_seen: &BitSet<CounterId>,
+    zero_expressions: &ZeroExpressions,
+    term: CovTerm,
+) -> bool {
+    match term {
+        CovTerm::Zero => true,
+        CovTerm::Counter(id) => !counters_seen.contains(id),
+        CovTerm::Expression(id) => zero_expressions.contains(id),
+    }
+}
diff --git a/tests/coverage-map/fn_sig_into_try.cov-map b/tests/coverage-map/fn_sig_into_try.cov-map
index 4672e7c1ce9..6e26c61aac9 100644
--- a/tests/coverage-map/fn_sig_into_try.cov-map
+++ b/tests/coverage-map/fn_sig_into_try.cov-map
@@ -7,47 +7,47 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 10, 1) to (start + 4, 2)
 
 Function name: fn_sig_into_try::b
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 10, 01, 02, 0f, 00, 02, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 10, 01, 02, 0f, 00, 02, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15)
 - Code(Zero) at (prev + 2, 15) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
-    = (c0 - c1)
+    = (c0 - Zero)
 - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+    = (Zero + (c0 - Zero))
 
 Function name: fn_sig_into_try::c
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 16, 01, 02, 17, 00, 02, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 16, 01, 02, 17, 00, 02, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 22, 1) to (start + 2, 23)
 - Code(Zero) at (prev + 2, 23) to (start + 0, 24)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
-    = (c0 - c1)
+    = (c0 - Zero)
 - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+    = (Zero + (c0 - Zero))
 
 Function name: fn_sig_into_try::d
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1c, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 1c, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 28, 1) to (start + 3, 15)
 - Code(Zero) at (prev + 3, 15) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
-    = (c0 - c1)
+    = (c0 - Zero)
 - Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+    = (Zero + (c0 - Zero))
 
diff --git a/tests/coverage-map/status-quo/bad_counter_ids.cov-map b/tests/coverage-map/status-quo/bad_counter_ids.cov-map
new file mode 100644
index 00000000000..0b8081acfa6
--- /dev/null
+++ b/tests/coverage-map/status-quo/bad_counter_ids.cov-map
@@ -0,0 +1,98 @@
+Function name: <bad_counter_ids::Foo as core::cmp::PartialEq>::eq
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 11, 00, 1a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 12, 17) to (start + 0, 26)
+
+Function name: <bad_counter_ids::Foo as core::fmt::Debug>::fmt
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 0a, 00, 0f]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 12, 10) to (start + 0, 15)
+
+Function name: bad_counter_ids::eq_bad
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 23, 01, 02, 1f, 00, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 35, 1) to (start + 2, 31)
+- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
+
+Function name: bad_counter_ids::eq_bad_message
+Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 28, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 40, 1) to (start + 2, 15)
+- Code(Expression(0, Sub)) at (prev + 2, 32) to (start + 0, 43)
+    = (c0 - Zero)
+- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
+
+Function name: bad_counter_ids::eq_good
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 01, 02, 1f, 05, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 31)
+- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
+
+Function name: bad_counter_ids::eq_good_message
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 14, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 20, 1) to (start + 2, 15)
+- Code(Zero) at (prev + 2, 32) to (start + 0, 43)
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
+
+Function name: bad_counter_ids::ne_bad
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 2d, 01, 02, 1f, 00, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 45, 1) to (start + 2, 31)
+- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
+
+Function name: bad_counter_ids::ne_bad_message
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 32, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 50, 1) to (start + 2, 15)
+- Code(Counter(1)) at (prev + 2, 32) to (start + 0, 43)
+- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
+
+Function name: bad_counter_ids::ne_good
+Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 19, 01, 02, 1f, 02, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 25, 1) to (start + 2, 31)
+- Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2)
+    = (c0 - Zero)
+
+Function name: bad_counter_ids::ne_good_message
+Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1e, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 15)
+- Code(Zero) at (prev + 2, 32) to (start + 0, 43)
+- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2)
+    = (c0 - Zero)
+
diff --git a/tests/coverage-map/status-quo/bad_counter_ids.rs b/tests/coverage-map/status-quo/bad_counter_ids.rs
new file mode 100644
index 00000000000..ef5460102b7
--- /dev/null
+++ b/tests/coverage-map/status-quo/bad_counter_ids.rs
@@ -0,0 +1,66 @@
+#![feature(coverage_attribute)]
+// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3
+
+// Regression test for <https://github.com/rust-lang/rust/issues/117012>.
+//
+// If some coverage counters were removed by MIR optimizations, we need to take
+// care not to refer to those counter IDs in coverage mappings, and instead
+// replace them with a constant zero value. If we don't, `llvm-cov` might see
+// a too-large counter ID and silently discard the entire function from its
+// coverage reports.
+
+#[derive(Debug, PartialEq, Eq)]
+struct Foo(u32);
+
+fn eq_good() {
+    println!("a");
+    assert_eq!(Foo(1), Foo(1));
+}
+
+fn eq_good_message() {
+    println!("b");
+    assert_eq!(Foo(1), Foo(1), "message b");
+}
+
+fn ne_good() {
+    println!("c");
+    assert_ne!(Foo(1), Foo(3));
+}
+
+fn ne_good_message() {
+    println!("d");
+    assert_ne!(Foo(1), Foo(3), "message d");
+}
+
+fn eq_bad() {
+    println!("e");
+    assert_eq!(Foo(1), Foo(3));
+}
+
+fn eq_bad_message() {
+    println!("f");
+    assert_eq!(Foo(1), Foo(3), "message f");
+}
+
+fn ne_bad() {
+    println!("g");
+    assert_ne!(Foo(1), Foo(1));
+}
+
+fn ne_bad_message() {
+    println!("h");
+    assert_ne!(Foo(1), Foo(1), "message h");
+}
+
+#[coverage(off)]
+fn main() {
+    eq_good();
+    eq_good_message();
+    ne_good();
+    ne_good_message();
+
+    assert!(std::panic::catch_unwind(eq_bad).is_err());
+    assert!(std::panic::catch_unwind(eq_bad_message).is_err());
+    assert!(std::panic::catch_unwind(ne_bad).is_err());
+    assert!(std::panic::catch_unwind(ne_bad_message).is_err());
+}
diff --git a/tests/coverage-map/status-quo/inline-dead.cov-map b/tests/coverage-map/status-quo/inline-dead.cov-map
index 06b64da5723..958b423f24c 100644
--- a/tests/coverage-map/status-quo/inline-dead.cov-map
+++ b/tests/coverage-map/status-quo/inline-dead.cov-map
@@ -7,19 +7,19 @@ Number of file 0 mappings: 1
 - Code(Zero) at (prev + 25, 1) to (start + 2, 2)
 
 Function name: inline_dead::live::<false>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 10, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02]
+Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 10, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 16, 1) to (start + 1, 9)
 - Code(Zero) at (prev + 2, 9) to (start + 0, 15)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10)
-    = (c0 - c1)
+    = (c0 - Zero)
 - Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+    = (Zero + (c0 - Zero))
 
 Function name: inline_dead::main
 Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0d, 01, 07, 06, 02, 02]
@@ -31,15 +31,15 @@ Number of file 0 mappings: 2
 - Code(Counter(0)) at (prev + 7, 6) to (start + 2, 2)
 
 Function name: inline_dead::main::{closure#0}
-Raw bytes (23): 0x[01, 01, 02, 09, 06, 01, 05, 03, 01, 07, 17, 00, 18, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06]
+Raw bytes (23): 0x[01, 01, 02, 00, 06, 01, 00, 03, 01, 07, 17, 00, 18, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
-- expression 0 operands: lhs = Counter(2), rhs = Expression(1, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 0 operands: lhs = Zero, rhs = Expression(1, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Zero
 Number of file 0 mappings: 3
 - Code(Counter(0)) at (prev + 7, 23) to (start + 0, 24)
 - Code(Zero) at (prev + 2, 13) to (start + 0, 14)
 - Code(Expression(0, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c2 + (c0 - c1))
+    = (Zero + (c0 - Zero))
 
diff --git a/tests/coverage-map/status-quo/issue-84561.cov-map b/tests/coverage-map/status-quo/issue-84561.cov-map
index 76340b1a78c..82582b309bf 100644
--- a/tests/coverage-map/status-quo/issue-84561.cov-map
+++ b/tests/coverage-map/status-quo/issue-84561.cov-map
@@ -85,47 +85,47 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 165, 9) to (start + 2, 10)
 
 Function name: issue_84561::test3
-Raw bytes (437): 0x[01, 01, 41, 05, 09, 0d, 11, 15, 19, 12, 1d, 15, 19, 21, 25, 1e, 29, 21, 25, 31, 39, 3d, 41, 2e, 45, 3d, 41, 42, 49, 45, 4d, 3f, 51, 42, 49, 45, 4d, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 59, 92, 01, 55, 51, 59, 8f, 01, 5d, 92, 01, 55, 51, 59, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 59, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 59, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 71, fe, 01, 82, 02, 71, 69, 6d, 69, 6d, 82, 02, 71, 69, 6d, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, ee, 01, 81, 01, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 33, 01, 06, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 71, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
+Raw bytes (436): 0x[01, 01, 41, 05, 09, 0d, 00, 15, 19, 12, 00, 15, 19, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 41, 2e, 45, 3d, 41, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 71, fe, 01, 82, 02, 71, 69, 6d, 69, 6d, 82, 02, 71, 69, 6d, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 71, fe, 01, 82, 02, 71, 69, 6d, 33, 01, 06, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 71, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 65
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 1 operands: lhs = Counter(3), rhs = Zero
 - expression 2 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 3 operands: lhs = Expression(4, Sub), rhs = Counter(7)
+- expression 3 operands: lhs = Expression(4, Sub), rhs = Zero
 - expression 4 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 5 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(10)
-- expression 7 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 8 operands: lhs = Counter(12), rhs = Counter(14)
+- expression 5 operands: lhs = Counter(8), rhs = Zero
+- expression 6 operands: lhs = Expression(7, Sub), rhs = Zero
+- expression 7 operands: lhs = Counter(8), rhs = Zero
+- expression 8 operands: lhs = Counter(12), rhs = Zero
 - expression 9 operands: lhs = Counter(15), rhs = Counter(16)
 - expression 10 operands: lhs = Expression(11, Sub), rhs = Counter(17)
 - expression 11 operands: lhs = Counter(15), rhs = Counter(16)
 - expression 12 operands: lhs = Expression(16, Sub), rhs = Counter(18)
-- expression 13 operands: lhs = Counter(17), rhs = Counter(19)
+- expression 13 operands: lhs = Counter(17), rhs = Zero
 - expression 14 operands: lhs = Expression(15, Add), rhs = Counter(20)
 - expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(18)
-- expression 16 operands: lhs = Counter(17), rhs = Counter(19)
+- expression 16 operands: lhs = Counter(17), rhs = Zero
 - expression 17 operands: lhs = Counter(23), rhs = Expression(34, Sub)
 - expression 18 operands: lhs = Expression(35, Add), rhs = Counter(23)
 - expression 19 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 20 operands: lhs = Counter(20), rhs = Counter(22)
+- expression 20 operands: lhs = Counter(20), rhs = Zero
 - expression 21 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 22 operands: lhs = Counter(20), rhs = Counter(22)
+- expression 22 operands: lhs = Counter(20), rhs = Zero
 - expression 23 operands: lhs = Expression(35, Add), rhs = Counter(23)
 - expression 24 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 25 operands: lhs = Counter(20), rhs = Counter(22)
+- expression 25 operands: lhs = Counter(20), rhs = Zero
 - expression 26 operands: lhs = Expression(33, Add), rhs = Counter(24)
 - expression 27 operands: lhs = Counter(23), rhs = Expression(34, Sub)
 - expression 28 operands: lhs = Expression(35, Add), rhs = Counter(23)
 - expression 29 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 30 operands: lhs = Counter(20), rhs = Counter(22)
+- expression 30 operands: lhs = Counter(20), rhs = Zero
 - expression 31 operands: lhs = Expression(32, Sub), rhs = Counter(25)
 - expression 32 operands: lhs = Expression(33, Add), rhs = Counter(24)
 - expression 33 operands: lhs = Counter(23), rhs = Expression(34, Sub)
 - expression 34 operands: lhs = Expression(35, Add), rhs = Counter(23)
 - expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 36 operands: lhs = Counter(20), rhs = Counter(22)
+- expression 36 operands: lhs = Counter(20), rhs = Zero
 - expression 37 operands: lhs = Counter(29), rhs = Expression(61, Sub)
 - expression 38 operands: lhs = Expression(62, Add), rhs = Counter(30)
 - expression 39 operands: lhs = Counter(28), rhs = Expression(63, Sub)
@@ -147,7 +147,7 @@ Number of expressions: 65
 - expression 55 operands: lhs = Counter(28), rhs = Expression(63, Sub)
 - expression 56 operands: lhs = Expression(64, Sub), rhs = Counter(28)
 - expression 57 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 58 operands: lhs = Expression(59, Sub), rhs = Counter(32)
+- expression 58 operands: lhs = Expression(59, Sub), rhs = Zero
 - expression 59 operands: lhs = Expression(60, Add), rhs = Counter(31)
 - expression 60 operands: lhs = Counter(29), rhs = Expression(61, Sub)
 - expression 61 operands: lhs = Expression(62, Add), rhs = Counter(30)
@@ -161,27 +161,27 @@ Number of file 0 mappings: 51
     = (c1 - c2)
 - Code(Counter(3)) at (prev + 5, 5) to (start + 0, 31)
 - Code(Expression(1, Sub)) at (prev + 1, 5) to (start + 0, 31)
-    = (c3 - c4)
+    = (c3 - Zero)
 - Code(Counter(5)) at (prev + 1, 9) to (start + 1, 28)
 - Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 31)
     = (c5 - c6)
 - Code(Expression(3, Sub)) at (prev + 1, 5) to (start + 0, 15)
-    = ((c5 - c6) - c7)
+    = ((c5 - c6) - Zero)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 48)
 - Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15)
 - Code(Zero) at (prev + 3, 32) to (start + 0, 48)
 - Code(Zero) at (prev + 0, 51) to (start + 0, 65)
 - Code(Zero) at (prev + 0, 75) to (start + 0, 90)
 - Code(Expression(7, Sub)) at (prev + 1, 5) to (start + 0, 15)
-    = (c8 - c9)
+    = (c8 - Zero)
 - Code(Zero) at (prev + 5, 9) to (start + 3, 16)
 - Code(Zero) at (prev + 5, 13) to (start + 0, 27)
 - Code(Zero) at (prev + 2, 13) to (start + 0, 28)
 - Code(Expression(6, Sub)) at (prev + 4, 9) to (start + 5, 6)
-    = ((c8 - c9) - c10)
+    = ((c8 - Zero) - Zero)
 - Code(Counter(12)) at (prev + 6, 5) to (start + 3, 6)
 - Code(Expression(8, Sub)) at (prev + 4, 5) to (start + 3, 6)
-    = (c12 - c14)
+    = (c12 - Zero)
 - Code(Counter(15)) at (prev + 4, 9) to (start + 4, 6)
 - Code(Expression(11, Sub)) at (prev + 5, 8) to (start + 0, 15)
     = (c15 - c16)
@@ -189,24 +189,24 @@ Number of file 0 mappings: 51
 - Code(Expression(10, Sub)) at (prev + 5, 9) to (start + 3, 10)
     = ((c15 - c16) - c17)
 - Code(Expression(15, Add)) at (prev + 5, 8) to (start + 0, 15)
-    = ((c17 - c19) + c18)
+    = ((c17 - Zero) + c18)
 - Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19)
 - Code(Zero) at (prev + 3, 13) to (start + 0, 29)
 - Code(Expression(14, Sub)) at (prev + 3, 9) to (start + 0, 19)
-    = (((c17 - c19) + c18) - c20)
+    = (((c17 - Zero) + c18) - c20)
 - Code(Zero) at (prev + 3, 13) to (start + 0, 29)
 - Code(Expression(33, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c23 + (((c20 - c22) + c21) - c23))
+    = (c23 + (((c20 - Zero) + c21) - c23))
 - Code(Expression(35, Add)) at (prev + 1, 12) to (start + 0, 19)
-    = ((c20 - c22) + c21)
+    = ((c20 - Zero) + c21)
 - Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19)
 - Code(Expression(34, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = (((c20 - c22) + c21) - c23)
+    = (((c20 - Zero) + c21) - c23)
 - Code(Expression(32, Sub)) at (prev + 4, 5) to (start + 2, 19)
-    = ((c23 + (((c20 - c22) + c21) - c23)) - c24)
+    = ((c23 + (((c20 - Zero) + c21) - c23)) - c24)
 - Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19)
 - Code(Expression(31, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = (((c23 + (((c20 - c22) + c21) - c23)) - c24) - c25)
+    = (((c23 + (((c20 - Zero) + c21) - c23)) - c24) - c25)
 - Code(Expression(60, Add)) at (prev + 3, 5) to (start + 0, 15)
     = (c29 + ((c28 + ((c26 - c27) - c28)) - c30))
 - Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19)
@@ -225,7 +225,7 @@ Number of file 0 mappings: 51
 - Code(Expression(59, Sub)) at (prev + 2, 5) to (start + 0, 15)
     = ((c29 + ((c28 + ((c26 - c27) - c28)) - c30)) - c31)
 - Code(Expression(58, Sub)) at (prev + 3, 9) to (start + 0, 34)
-    = (((c29 + ((c28 + ((c26 - c27) - c28)) - c30)) - c31) - c32)
+    = (((c29 + ((c28 + ((c26 - c27) - c28)) - c30)) - c31) - Zero)
 - Code(Zero) at (prev + 2, 5) to (start + 0, 15)
 - Code(Zero) at (prev + 3, 9) to (start + 0, 44)
 - Code(Zero) at (prev + 2, 1) to (start + 0, 2)
diff --git a/tests/coverage-map/status-quo/loops_branches.cov-map b/tests/coverage-map/status-quo/loops_branches.cov-map
index ebace8cbd71..813583a9de7 100644
--- a/tests/coverage-map/status-quo/loops_branches.cov-map
+++ b/tests/coverage-map/status-quo/loops_branches.cov-map
@@ -1,177 +1,177 @@
 Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt
-Raw bytes (249): 0x[01, 01, 31, 05, 09, 00, 02, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 15, bf, 01, c3, 01, 0d, 00, 11, 15, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 15, b6, 01, 15, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 15, b2, 01, 1d, b6, 01, 15, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 15, 00, ae, 01, b2, 01, 1d, b6, 01, 15, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 15, ab, 01, 11, 00, ae, 01, b2, 01, 1d, b6, 01, 15, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 15, 25, a3, 01, a6, 01, 19, ab, 01, 11, 00, ae, 01, b2, 01, 1d, b6, 01, 15, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, b6, 01, 03, 0d, 00, 0e, bb, 01, 00, 12, 00, 17, b6, 01, 01, 10, 00, 14, b2, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, ae, 01, 01, 12, 00, 13, ab, 01, 01, 11, 00, 22, a6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 9f, 01, 01, 05, 00, 06]
+Raw bytes (249): 0x[01, 01, 31, 05, 00, 00, 02, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, bf, 01, c3, 01, 0d, 00, 11, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 25, a3, 01, a6, 01, 19, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, b6, 01, 03, 0d, 00, 0e, bb, 01, 00, 12, 00, 17, b6, 01, 01, 10, 00, 14, b2, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, ae, 01, 01, 12, 00, 13, ab, 01, 01, 11, 00, 22, a6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 9f, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 49
-- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 0 operands: lhs = Counter(1), rhs = Zero
 - expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 - expression 2 operands: lhs = Expression(46, Add), rhs = Counter(6)
 - expression 3 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 4 operands: lhs = Counter(3), rhs = Zero
-- expression 5 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 5 operands: lhs = Counter(4), rhs = Zero
 - expression 6 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 7 operands: lhs = Counter(3), rhs = Zero
-- expression 8 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 8 operands: lhs = Counter(4), rhs = Zero
 - expression 9 operands: lhs = Expression(46, Add), rhs = Counter(6)
 - expression 10 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 11 operands: lhs = Counter(3), rhs = Zero
-- expression 12 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 13 operands: lhs = Expression(45, Sub), rhs = Counter(5)
+- expression 12 operands: lhs = Counter(4), rhs = Zero
+- expression 13 operands: lhs = Expression(45, Sub), rhs = Zero
 - expression 14 operands: lhs = Expression(46, Add), rhs = Counter(6)
 - expression 15 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 16 operands: lhs = Counter(3), rhs = Zero
-- expression 17 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 18 operands: lhs = Expression(44, Sub), rhs = Counter(7)
-- expression 19 operands: lhs = Expression(45, Sub), rhs = Counter(5)
+- expression 17 operands: lhs = Counter(4), rhs = Zero
+- expression 18 operands: lhs = Expression(44, Sub), rhs = Zero
+- expression 19 operands: lhs = Expression(45, Sub), rhs = Zero
 - expression 20 operands: lhs = Expression(46, Add), rhs = Counter(6)
 - expression 21 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 22 operands: lhs = Counter(3), rhs = Zero
-- expression 23 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 23 operands: lhs = Counter(4), rhs = Zero
 - expression 24 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 25 operands: lhs = Expression(44, Sub), rhs = Counter(7)
-- expression 26 operands: lhs = Expression(45, Sub), rhs = Counter(5)
+- expression 25 operands: lhs = Expression(44, Sub), rhs = Zero
+- expression 26 operands: lhs = Expression(45, Sub), rhs = Zero
 - expression 27 operands: lhs = Expression(46, Add), rhs = Counter(6)
 - expression 28 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 29 operands: lhs = Counter(3), rhs = Zero
-- expression 30 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 30 operands: lhs = Counter(4), rhs = Zero
 - expression 31 operands: lhs = Expression(42, Add), rhs = Counter(4)
 - expression 32 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 33 operands: lhs = Expression(44, Sub), rhs = Counter(7)
-- expression 34 operands: lhs = Expression(45, Sub), rhs = Counter(5)
+- expression 33 operands: lhs = Expression(44, Sub), rhs = Zero
+- expression 34 operands: lhs = Expression(45, Sub), rhs = Zero
 - expression 35 operands: lhs = Expression(46, Add), rhs = Counter(6)
 - expression 36 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 37 operands: lhs = Counter(3), rhs = Zero
-- expression 38 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 38 operands: lhs = Counter(4), rhs = Zero
 - expression 39 operands: lhs = Counter(9), rhs = Expression(40, Add)
 - expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(6)
 - expression 41 operands: lhs = Expression(42, Add), rhs = Counter(4)
 - expression 42 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 43 operands: lhs = Expression(44, Sub), rhs = Counter(7)
-- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(5)
+- expression 43 operands: lhs = Expression(44, Sub), rhs = Zero
+- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero
 - expression 45 operands: lhs = Expression(46, Add), rhs = Counter(6)
 - expression 46 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
 - expression 47 operands: lhs = Counter(3), rhs = Zero
-- expression 48 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 48 operands: lhs = Counter(4), rhs = Zero
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21)
 - Code(Zero) at (prev + 1, 23) to (start + 0, 27)
 - Code(Zero) at (prev + 0, 28) to (start + 0, 30)
 - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15)
-    = (c1 - c2)
+    = (c1 - Zero)
 - Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = (Zero + (c1 - c2))
+    = (Zero + (c1 - Zero))
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
 - Code(Zero) at (prev + 1, 16) to (start + 1, 10)
 - Code(Expression(45, Sub)) at (prev + 3, 13) to (start + 0, 14)
-    = (((c3 + Zero) + (c4 + c5)) - c6)
+    = (((c3 + Zero) + (c4 + Zero)) - c6)
 - Code(Expression(46, Add)) at (prev + 0, 18) to (start + 0, 23)
-    = ((c3 + Zero) + (c4 + c5))
+    = ((c3 + Zero) + (c4 + Zero))
 - Code(Expression(45, Sub)) at (prev + 1, 16) to (start + 0, 20)
-    = (((c3 + Zero) + (c4 + c5)) - c6)
+    = (((c3 + Zero) + (c4 + Zero)) - c6)
 - Code(Expression(44, Sub)) at (prev + 1, 20) to (start + 0, 25)
-    = ((((c3 + Zero) + (c4 + c5)) - c6) - c5)
+    = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
 - Code(Expression(43, Sub)) at (prev + 1, 18) to (start + 0, 19)
-    = (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)
+    = (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)
 - Code(Expression(42, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = (Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7))
+    = (Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero))
 - Code(Expression(41, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4)
+    = ((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4)
 - Code(Zero) at (prev + 1, 20) to (start + 1, 14)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
 - Code(Expression(39, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = (c9 + (((Zero + (((((c3 + Zero) + (c4 + c5)) - c6) - c5) - c7)) - c4) + c6))
+    = (c9 + (((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4) + c6))
 
 Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt
-Raw bytes (253): 0x[01, 01, 33, 01, 05, 02, 09, 00, 0e, 02, 09, bf, 01, 19, c3, 01, c7, 01, 05, 0d, 11, 15, c3, 01, c7, 01, 05, 0d, 11, 15, bf, 01, 19, c3, 01, c7, 01, 05, 0d, 11, 15, ba, 01, 11, bf, 01, 19, c3, 01, c7, 01, 05, 0d, 11, 15, b6, 01, 1d, ba, 01, 11, bf, 01, 19, c3, 01, c7, 01, 05, 0d, 11, 15, 00, b2, 01, b6, 01, 1d, ba, 01, 11, bf, 01, 19, c3, 01, c7, 01, 05, 0d, 11, 15, af, 01, 15, 00, b2, 01, b6, 01, 1d, ba, 01, 11, bf, 01, 19, c3, 01, c7, 01, 05, 0d, 11, 15, aa, 01, cb, 01, af, 01, 15, 00, b2, 01, b6, 01, 1d, ba, 01, 11, bf, 01, 19, c3, 01, c7, 01, 05, 0d, 11, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, ba, 01, 02, 0d, 00, 0e, bf, 01, 00, 12, 00, 17, ba, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, b6, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b2, 01, 01, 12, 00, 13, af, 01, 01, 11, 00, 22, aa, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, a7, 01, 01, 05, 00, 06]
+Raw bytes (253): 0x[01, 01, 33, 01, 00, 02, 00, 00, 0e, 02, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, c3, 01, c7, 01, 00, 0d, 00, 15, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, 00, b2, 01, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, af, 01, 15, 00, b2, 01, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, aa, 01, cb, 01, af, 01, 15, 00, b2, 01, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, ba, 01, 02, 0d, 00, 0e, bf, 01, 00, 12, 00, 17, ba, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, b6, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b2, 01, 01, 12, 00, 13, af, 01, 01, 11, 00, 22, aa, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, a7, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 51
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Sub), rhs = Counter(2)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Expression(0, Sub), rhs = Zero
 - expression 2 operands: lhs = Zero, rhs = Expression(3, Sub)
-- expression 3 operands: lhs = Expression(0, Sub), rhs = Counter(2)
+- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero
 - expression 4 operands: lhs = Expression(47, Add), rhs = Counter(6)
 - expression 5 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 6 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 7 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 6 operands: lhs = Zero, rhs = Counter(3)
+- expression 7 operands: lhs = Zero, rhs = Counter(5)
 - expression 8 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 9 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 10 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 9 operands: lhs = Zero, rhs = Counter(3)
+- expression 10 operands: lhs = Zero, rhs = Counter(5)
 - expression 11 operands: lhs = Expression(47, Add), rhs = Counter(6)
 - expression 12 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 13 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 14 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 15 operands: lhs = Expression(46, Sub), rhs = Counter(4)
+- expression 13 operands: lhs = Zero, rhs = Counter(3)
+- expression 14 operands: lhs = Zero, rhs = Counter(5)
+- expression 15 operands: lhs = Expression(46, Sub), rhs = Zero
 - expression 16 operands: lhs = Expression(47, Add), rhs = Counter(6)
 - expression 17 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 18 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 19 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 20 operands: lhs = Expression(45, Sub), rhs = Counter(7)
-- expression 21 operands: lhs = Expression(46, Sub), rhs = Counter(4)
+- expression 18 operands: lhs = Zero, rhs = Counter(3)
+- expression 19 operands: lhs = Zero, rhs = Counter(5)
+- expression 20 operands: lhs = Expression(45, Sub), rhs = Zero
+- expression 21 operands: lhs = Expression(46, Sub), rhs = Zero
 - expression 22 operands: lhs = Expression(47, Add), rhs = Counter(6)
 - expression 23 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 24 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 25 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 24 operands: lhs = Zero, rhs = Counter(3)
+- expression 25 operands: lhs = Zero, rhs = Counter(5)
 - expression 26 operands: lhs = Zero, rhs = Expression(44, Sub)
-- expression 27 operands: lhs = Expression(45, Sub), rhs = Counter(7)
-- expression 28 operands: lhs = Expression(46, Sub), rhs = Counter(4)
+- expression 27 operands: lhs = Expression(45, Sub), rhs = Zero
+- expression 28 operands: lhs = Expression(46, Sub), rhs = Zero
 - expression 29 operands: lhs = Expression(47, Add), rhs = Counter(6)
 - expression 30 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 31 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 32 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 31 operands: lhs = Zero, rhs = Counter(3)
+- expression 32 operands: lhs = Zero, rhs = Counter(5)
 - expression 33 operands: lhs = Expression(43, Add), rhs = Counter(5)
 - expression 34 operands: lhs = Zero, rhs = Expression(44, Sub)
-- expression 35 operands: lhs = Expression(45, Sub), rhs = Counter(7)
-- expression 36 operands: lhs = Expression(46, Sub), rhs = Counter(4)
+- expression 35 operands: lhs = Expression(45, Sub), rhs = Zero
+- expression 36 operands: lhs = Expression(46, Sub), rhs = Zero
 - expression 37 operands: lhs = Expression(47, Add), rhs = Counter(6)
 - expression 38 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 39 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 40 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 39 operands: lhs = Zero, rhs = Counter(3)
+- expression 40 operands: lhs = Zero, rhs = Counter(5)
 - expression 41 operands: lhs = Expression(42, Sub), rhs = Expression(50, Add)
 - expression 42 operands: lhs = Expression(43, Add), rhs = Counter(5)
 - expression 43 operands: lhs = Zero, rhs = Expression(44, Sub)
-- expression 44 operands: lhs = Expression(45, Sub), rhs = Counter(7)
-- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(4)
+- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero
+- expression 45 operands: lhs = Expression(46, Sub), rhs = Zero
 - expression 46 operands: lhs = Expression(47, Add), rhs = Counter(6)
 - expression 47 operands: lhs = Expression(48, Add), rhs = Expression(49, Add)
-- expression 48 operands: lhs = Counter(1), rhs = Counter(3)
-- expression 49 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 48 operands: lhs = Zero, rhs = Counter(3)
+- expression 49 operands: lhs = Zero, rhs = Counter(5)
 - expression 50 operands: lhs = Counter(6), rhs = Counter(9)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17)
 - Code(Zero) at (prev + 1, 18) to (start + 1, 10)
 - Code(Expression(0, Sub)) at (prev + 2, 16) to (start + 0, 21)
-    = (c0 - c1)
+    = (c0 - Zero)
 - Code(Zero) at (prev + 1, 23) to (start + 0, 27)
 - Code(Zero) at (prev + 0, 28) to (start + 0, 30)
 - Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 15)
-    = ((c0 - c1) - c2)
+    = ((c0 - Zero) - Zero)
 - Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = (Zero + ((c0 - c1) - c2))
+    = (Zero + ((c0 - Zero) - Zero))
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
 - Code(Expression(46, Sub)) at (prev + 2, 13) to (start + 0, 14)
-    = (((c1 + c3) + (c4 + c5)) - c6)
+    = (((Zero + c3) + (Zero + c5)) - c6)
 - Code(Expression(47, Add)) at (prev + 0, 18) to (start + 0, 23)
-    = ((c1 + c3) + (c4 + c5))
+    = ((Zero + c3) + (Zero + c5))
 - Code(Expression(46, Sub)) at (prev + 1, 16) to (start + 0, 21)
-    = (((c1 + c3) + (c4 + c5)) - c6)
+    = (((Zero + c3) + (Zero + c5)) - c6)
 - Code(Zero) at (prev + 0, 22) to (start + 1, 14)
 - Code(Expression(45, Sub)) at (prev + 2, 20) to (start + 0, 25)
-    = ((((c1 + c3) + (c4 + c5)) - c6) - c4)
+    = ((((Zero + c3) + (Zero + c5)) - c6) - Zero)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
 - Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 19)
-    = (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)
+    = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)
 - Code(Expression(43, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = (Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7))
+    = (Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero))
 - Code(Expression(42, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5)
+    = ((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
 - Code(Expression(41, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = (((Zero + (((((c1 + c3) + (c4 + c5)) - c6) - c4) - c7)) - c5) + (c6 + c9))
+    = (((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5) + (c6 + c9))
 
 Function name: loops_branches::main
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02]
diff --git a/tests/coverage-map/status-quo/sort_groups.cov-map b/tests/coverage-map/status-quo/sort_groups.cov-map
index 7156a66cf89..db027f3dc32 100644
--- a/tests/coverage-map/status-quo/sort_groups.cov-map
+++ b/tests/coverage-map/status-quo/sort_groups.cov-map
@@ -44,19 +44,19 @@ Number of file 0 mappings: 4
     = (c1 + (c0 - c1))
 
 Function name: sort_groups::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 06, 01, 04, 0d, 00, 04, 0e, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 02, 02]
+Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 06, 01, 04, 0d, 00, 04, 0e, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 02, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 6, 1) to (start + 4, 13)
 - Code(Zero) at (prev + 4, 14) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = (c0 - c1)
+    = (c0 - Zero)
 - Code(Expression(1, Add)) at (prev + 1, 5) to (start + 2, 2)
-    = (c1 + (c0 - c1))
+    = (Zero + (c0 - Zero))
 
 Function name: sort_groups::other_fn
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11]
diff --git a/tests/coverage-map/status-quo/tight_inf_loop.cov-map b/tests/coverage-map/status-quo/tight_inf_loop.cov-map
index 76884212c14..7fe3146b080 100644
--- a/tests/coverage-map/status-quo/tight_inf_loop.cov-map
+++ b/tests/coverage-map/status-quo/tight_inf_loop.cov-map
@@ -1,12 +1,12 @@
 Function name: tight_inf_loop::main
-Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 01, 01, 01, 0d, 00, 02, 09, 00, 10, 02, 01, 06, 01, 02]
+Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 01, 01, 01, 0d, 00, 02, 09, 00, 10, 02, 01, 06, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 1
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
 Number of file 0 mappings: 3
 - Code(Counter(0)) at (prev + 1, 1) to (start + 1, 13)
 - Code(Zero) at (prev + 2, 9) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 1, 2)
-    = (c0 - c1)
+    = (c0 - Zero)
 
diff --git a/tests/coverage-map/status-quo/while.cov-map b/tests/coverage-map/status-quo/while.cov-map
index cfd2be96a0d..af250f3fb71 100644
--- a/tests/coverage-map/status-quo/while.cov-map
+++ b/tests/coverage-map/status-quo/while.cov-map
@@ -1,15 +1,15 @@
 Function name: while::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 03, 05, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 01, 06, 06, 02, 01, 00, 02]
+Raw bytes (28): 0x[01, 01, 02, 01, 00, 03, 00, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 01, 06, 06, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1)
+- expression 0 operands: lhs = Counter(0), rhs = Zero
+- expression 1 operands: lhs = Expression(0, Add), rhs = Zero
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16)
 - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 20)
-    = (c0 + c1)
+    = (c0 + Zero)
 - Code(Zero) at (prev + 0, 21) to (start + 1, 6)
 - Code(Expression(1, Sub)) at (prev + 2, 1) to (start + 0, 2)
-    = ((c0 + c1) - c1)
+    = ((c0 + Zero) - Zero)
 
diff --git a/tests/run-coverage/bad_counter_ids.coverage b/tests/run-coverage/bad_counter_ids.coverage
new file mode 100644
index 00000000000..d69ebf160ea
--- /dev/null
+++ b/tests/run-coverage/bad_counter_ids.coverage
@@ -0,0 +1,69 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3
+   LL|       |
+   LL|       |// Regression test for <https://github.com/rust-lang/rust/issues/117012>.
+   LL|       |//
+   LL|       |// If some coverage counters were removed by MIR optimizations, we need to take
+   LL|       |// care not to refer to those counter IDs in coverage mappings, and instead
+   LL|       |// replace them with a constant zero value. If we don't, `llvm-cov` might see
+   LL|       |// a too-large counter ID and silently discard the entire function from its
+   LL|       |// coverage reports.
+   LL|       |
+   LL|      8|#[derive(Debug, PartialEq, Eq)]
+   LL|       |struct Foo(u32);
+   LL|       |
+   LL|      1|fn eq_good() {
+   LL|      1|    println!("a");
+   LL|      1|    assert_eq!(Foo(1), Foo(1));
+   LL|      1|}
+   LL|       |
+   LL|      1|fn eq_good_message() {
+   LL|      1|    println!("b");
+   LL|      1|    assert_eq!(Foo(1), Foo(1), "message b");
+                                             ^0
+   LL|      1|}
+   LL|       |
+   LL|      1|fn ne_good() {
+   LL|      1|    println!("c");
+   LL|      1|    assert_ne!(Foo(1), Foo(3));
+   LL|      1|}
+   LL|       |
+   LL|      1|fn ne_good_message() {
+   LL|      1|    println!("d");
+   LL|      1|    assert_ne!(Foo(1), Foo(3), "message d");
+                                             ^0
+   LL|      1|}
+   LL|       |
+   LL|      1|fn eq_bad() {
+   LL|      1|    println!("e");
+   LL|      1|    assert_eq!(Foo(1), Foo(3));
+   LL|      0|}
+   LL|       |
+   LL|      1|fn eq_bad_message() {
+   LL|      1|    println!("f");
+   LL|      1|    assert_eq!(Foo(1), Foo(3), "message f");
+   LL|      0|}
+   LL|       |
+   LL|      1|fn ne_bad() {
+   LL|      1|    println!("g");
+   LL|      1|    assert_ne!(Foo(1), Foo(1));
+   LL|      0|}
+   LL|       |
+   LL|      1|fn ne_bad_message() {
+   LL|      1|    println!("h");
+   LL|      1|    assert_ne!(Foo(1), Foo(1), "message h");
+   LL|      0|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    eq_good();
+   LL|       |    eq_good_message();
+   LL|       |    ne_good();
+   LL|       |    ne_good_message();
+   LL|       |
+   LL|       |    assert!(std::panic::catch_unwind(eq_bad).is_err());
+   LL|       |    assert!(std::panic::catch_unwind(eq_bad_message).is_err());
+   LL|       |    assert!(std::panic::catch_unwind(ne_bad).is_err());
+   LL|       |    assert!(std::panic::catch_unwind(ne_bad_message).is_err());
+   LL|       |}
+
diff --git a/tests/run-coverage/bad_counter_ids.rs b/tests/run-coverage/bad_counter_ids.rs
new file mode 100644
index 00000000000..ef5460102b7
--- /dev/null
+++ b/tests/run-coverage/bad_counter_ids.rs
@@ -0,0 +1,66 @@
+#![feature(coverage_attribute)]
+// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3
+
+// Regression test for <https://github.com/rust-lang/rust/issues/117012>.
+//
+// If some coverage counters were removed by MIR optimizations, we need to take
+// care not to refer to those counter IDs in coverage mappings, and instead
+// replace them with a constant zero value. If we don't, `llvm-cov` might see
+// a too-large counter ID and silently discard the entire function from its
+// coverage reports.
+
+#[derive(Debug, PartialEq, Eq)]
+struct Foo(u32);
+
+fn eq_good() {
+    println!("a");
+    assert_eq!(Foo(1), Foo(1));
+}
+
+fn eq_good_message() {
+    println!("b");
+    assert_eq!(Foo(1), Foo(1), "message b");
+}
+
+fn ne_good() {
+    println!("c");
+    assert_ne!(Foo(1), Foo(3));
+}
+
+fn ne_good_message() {
+    println!("d");
+    assert_ne!(Foo(1), Foo(3), "message d");
+}
+
+fn eq_bad() {
+    println!("e");
+    assert_eq!(Foo(1), Foo(3));
+}
+
+fn eq_bad_message() {
+    println!("f");
+    assert_eq!(Foo(1), Foo(3), "message f");
+}
+
+fn ne_bad() {
+    println!("g");
+    assert_ne!(Foo(1), Foo(1));
+}
+
+fn ne_bad_message() {
+    println!("h");
+    assert_ne!(Foo(1), Foo(1), "message h");
+}
+
+#[coverage(off)]
+fn main() {
+    eq_good();
+    eq_good_message();
+    ne_good();
+    ne_good_message();
+
+    assert!(std::panic::catch_unwind(eq_bad).is_err());
+    assert!(std::panic::catch_unwind(eq_bad_message).is_err());
+    assert!(std::panic::catch_unwind(ne_bad).is_err());
+    assert!(std::panic::catch_unwind(ne_bad_message).is_err());
+}