summaryrefslogtreecommitdiffstats
path: root/tests/coverage
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:42 +0000
commitcec1877e180393eba0f6ddb0cf97bf3a791631c7 (patch)
tree47b4dac2a9dd9a40c30c251b4d4a72d7ccf77e9f /tests/coverage
parentAdding debian version 1.74.1+dfsg1-1. (diff)
downloadrustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.tar.xz
rustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/coverage')
-rw-r--r--tests/coverage/README.md16
-rw-r--r--tests/coverage/abort.cov-map57
-rw-r--r--tests/coverage/abort.coverage69
-rw-r--r--tests/coverage/abort.rs66
-rw-r--r--tests/coverage/assert.cov-map40
-rw-r--r--tests/coverage/assert.coverage34
-rw-r--r--tests/coverage/assert.rs32
-rw-r--r--tests/coverage/async.cov-map326
-rw-r--r--tests/coverage/async.coverage139
-rw-r--r--tests/coverage/async.rs128
-rw-r--r--tests/coverage/async2.cov-map132
-rw-r--r--tests/coverage/async2.coverage104
-rw-r--r--tests/coverage/async2.rs57
-rw-r--r--tests/coverage/auxiliary/inline_always_with_dead_code.rs22
-rw-r--r--tests/coverage/auxiliary/macro_name_span_helper.rs10
-rw-r--r--tests/coverage/auxiliary/unused_mod_helper.rs4
-rw-r--r--tests/coverage/auxiliary/used_crate.rs103
-rw-r--r--tests/coverage/auxiliary/used_inline_crate.rs85
-rw-r--r--tests/coverage/bad_counter_ids.cov-map98
-rw-r--r--tests/coverage/bad_counter_ids.coverage69
-rw-r--r--tests/coverage/bad_counter_ids.rs66
-rw-r--r--tests/coverage/closure.cov-map275
-rw-r--r--tests/coverage/closure.coverage227
-rw-r--r--tests/coverage/closure.rs220
-rw-r--r--tests/coverage/closure_bug.cov-map133
-rw-r--r--tests/coverage/closure_bug.coverage53
-rw-r--r--tests/coverage/closure_bug.rs44
-rw-r--r--tests/coverage/closure_macro.cov-map36
-rw-r--r--tests/coverage/closure_macro.coverage42
-rw-r--r--tests/coverage/closure_macro.rs40
-rw-r--r--tests/coverage/closure_macro_async.cov-map44
-rw-r--r--tests/coverage/closure_macro_async.coverage79
-rw-r--r--tests/coverage/closure_macro_async.rs77
-rw-r--r--tests/coverage/conditions.cov-map259
-rw-r--r--tests/coverage/conditions.coverage93
-rw-r--r--tests/coverage/conditions.rs86
-rw-r--r--tests/coverage/continue.cov-map79
-rw-r--r--tests/coverage/continue.coverage70
-rw-r--r--tests/coverage/continue.rs69
-rw-r--r--tests/coverage/coroutine.cov-map53
-rw-r--r--tests/coverage/coroutine.coverage32
-rw-r--r--tests/coverage/coroutine.rs30
-rw-r--r--tests/coverage/dead_code.cov-map37
-rw-r--r--tests/coverage/dead_code.coverage39
-rw-r--r--tests/coverage/dead_code.rs37
-rw-r--r--tests/coverage/drop_trait.cov-map21
-rw-r--r--tests/coverage/drop_trait.coverage34
-rw-r--r--tests/coverage/drop_trait.rs33
-rw-r--r--tests/coverage/fn_sig_into_try.cov-map53
-rw-r--r--tests/coverage/fn_sig_into_try.coverage45
-rw-r--r--tests/coverage/fn_sig_into_try.rs41
-rw-r--r--tests/coverage/generics.cov-map45
-rw-r--r--tests/coverage/generics.coverage67
-rw-r--r--tests/coverage/generics.rs44
-rw-r--r--tests/coverage/if.cov-map15
-rw-r--r--tests/coverage/if.coverage30
-rw-r--r--tests/coverage/if.rs28
-rw-r--r--tests/coverage/if_else.cov-map25
-rw-r--r--tests/coverage/if_else.coverage41
-rw-r--r--tests/coverage/if_else.rs40
-rw-r--r--tests/coverage/inline-dead.cov-map45
-rw-r--r--tests/coverage/inline-dead.coverage28
-rw-r--r--tests/coverage/inline-dead.rs27
-rw-r--r--tests/coverage/inline.cov-map78
-rw-r--r--tests/coverage/inline.coverage54
-rw-r--r--tests/coverage/inline.rs51
-rw-r--r--tests/coverage/inner_items.cov-map49
-rw-r--r--tests/coverage/inner_items.coverage60
-rw-r--r--tests/coverage/inner_items.rs57
-rw-r--r--tests/coverage/issue-83601.cov-map28
-rw-r--r--tests/coverage/issue-83601.coverage16
-rw-r--r--tests/coverage/issue-83601.rs14
-rw-r--r--tests/coverage/issue-84561.cov-map232
-rw-r--r--tests/coverage/issue-84561.coverage189
-rw-r--r--tests/coverage/issue-84561.rs182
-rw-r--r--tests/coverage/issue-85461.cov-map8
-rw-r--r--tests/coverage/issue-85461.coverage37
-rw-r--r--tests/coverage/issue-85461.rs11
-rw-r--r--tests/coverage/issue-93054.cov-map24
-rw-r--r--tests/coverage/issue-93054.coverage31
-rw-r--r--tests/coverage/issue-93054.rs30
-rw-r--r--tests/coverage/lazy_boolean.cov-map219
-rw-r--r--tests/coverage/lazy_boolean.coverage64
-rw-r--r--tests/coverage/lazy_boolean.rs61
-rw-r--r--tests/coverage/long_and_wide.cov-map32
-rw-r--r--tests/coverage/long_and_wide.coverage151
-rw-r--r--tests/coverage/long_and_wide.rs150
-rw-r--r--tests/coverage/loop_break_value.cov-map8
-rw-r--r--tests/coverage/loop_break_value.coverage14
-rw-r--r--tests/coverage/loop_break_value.rs13
-rw-r--r--tests/coverage/loops_branches.cov-map183
-rw-r--r--tests/coverage/loops_branches.coverage67
-rw-r--r--tests/coverage/loops_branches.rs60
-rw-r--r--tests/coverage/macro_name_span.cov-map16
-rw-r--r--tests/coverage/macro_name_span.coverage39
-rw-r--r--tests/coverage/macro_name_span.rs25
-rw-r--r--tests/coverage/match_or_pattern.cov-map83
-rw-r--r--tests/coverage/match_or_pattern.coverage48
-rw-r--r--tests/coverage/match_or_pattern.rs43
-rw-r--r--tests/coverage/nested_loops.cov-map51
-rw-r--r--tests/coverage/nested_loops.coverage26
-rw-r--r--tests/coverage/nested_loops.rs25
-rw-r--r--tests/coverage/no_cov_crate.cov-map78
-rw-r--r--tests/coverage/no_cov_crate.coverage89
-rw-r--r--tests/coverage/no_cov_crate.rs88
-rw-r--r--tests/coverage/overflow.cov-map43
-rw-r--r--tests/coverage/overflow.coverage65
-rw-r--r--tests/coverage/overflow.rs64
-rw-r--r--tests/coverage/panic_unwind.cov-map40
-rw-r--r--tests/coverage/panic_unwind.coverage32
-rw-r--r--tests/coverage/panic_unwind.rs31
-rw-r--r--tests/coverage/partial_eq.cov-map64
-rw-r--r--tests/coverage/partial_eq.coverage48
-rw-r--r--tests/coverage/partial_eq.rs46
-rw-r--r--tests/coverage/simple_loop.cov-map27
-rw-r--r--tests/coverage/simple_loop.coverage37
-rw-r--r--tests/coverage/simple_loop.rs35
-rw-r--r--tests/coverage/simple_match.cov-map33
-rw-r--r--tests/coverage/simple_match.coverage45
-rw-r--r--tests/coverage/simple_match.rs43
-rw-r--r--tests/coverage/sort_groups.cov-map83
-rw-r--r--tests/coverage/sort_groups.coverage49
-rw-r--r--tests/coverage/sort_groups.rs23
-rw-r--r--tests/coverage/test_harness.cov-map24
-rw-r--r--tests/coverage/test_harness.coverage11
-rw-r--r--tests/coverage/test_harness.rs10
-rw-r--r--tests/coverage/tight_inf_loop.cov-map12
-rw-r--r--tests/coverage/tight_inf_loop.coverage6
-rw-r--r--tests/coverage/tight_inf_loop.rs5
-rw-r--r--tests/coverage/trivial.cov-map8
-rw-r--r--tests/coverage/trivial.coverage4
-rw-r--r--tests/coverage/trivial.rs3
-rw-r--r--tests/coverage/try_error_result.cov-map220
-rw-r--r--tests/coverage/try_error_result.coverage125
-rw-r--r--tests/coverage/try_error_result.rs118
-rw-r--r--tests/coverage/unreachable.cov-map24
-rw-r--r--tests/coverage/unreachable.coverage38
-rw-r--r--tests/coverage/unreachable.rs37
-rw-r--r--tests/coverage/unused.cov-map94
-rw-r--r--tests/coverage/unused.coverage64
-rw-r--r--tests/coverage/unused.rs41
-rw-r--r--tests/coverage/unused_mod.cov-map16
-rw-r--r--tests/coverage/unused_mod.coverage14
-rw-r--r--tests/coverage/unused_mod.rs6
-rw-r--r--tests/coverage/uses_crate.cov-map40
-rw-r--r--tests/coverage/uses_crate.coverage173
-rw-r--r--tests/coverage/uses_crate.rs19
-rw-r--r--tests/coverage/uses_inline_crate.cov-map55
-rw-r--r--tests/coverage/uses_inline_crate.coverage159
-rw-r--r--tests/coverage/uses_inline_crate.rs22
-rw-r--r--tests/coverage/while.cov-map15
-rw-r--r--tests/coverage/while.coverage6
-rw-r--r--tests/coverage/while.rs5
-rw-r--r--tests/coverage/while_early_ret.cov-map26
-rw-r--r--tests/coverage/while_early_ret.coverage43
-rw-r--r--tests/coverage/while_early_ret.rs42
-rw-r--r--tests/coverage/yield.cov-map62
-rw-r--r--tests/coverage/yield.coverage38
-rw-r--r--tests/coverage/yield.rs37
159 files changed, 9687 insertions, 0 deletions
diff --git a/tests/coverage/README.md b/tests/coverage/README.md
new file mode 100644
index 000000000..c72aa69c0
--- /dev/null
+++ b/tests/coverage/README.md
@@ -0,0 +1,16 @@
+The tests in this directory are shared by two different test modes, and can be
+run in multiple different ways:
+
+- `./x.py test coverage-map` (compiles to LLVM IR and checks coverage mappings)
+- `./x.py test coverage-run` (runs a test binary and checks its coverage report)
+- `./x.py test coverage` (runs both `coverage-map` and `coverage-run`)
+
+## Maintenance note
+
+These tests can be sensitive to small changes in MIR spans or MIR control flow,
+especially in HIR-to-MIR lowering or MIR optimizations.
+
+If you haven't touched the coverage code directly, and the tests still pass in
+`coverage-run` mode, then it should usually be OK to just re-bless the mappings
+as necessary with `./x.py test coverage-map --bless`, without worrying too much
+about the exact changes.
diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map
new file mode 100644
index 000000000..45d3795ef
--- /dev/null
+++ b/tests/coverage/abort.cov-map
@@ -0,0 +1,57 @@
+Function name: abort::main
+Raw bytes (105): 0x[01, 01, 12, 01, 47, 05, 09, 03, 0d, 42, 11, 03, 0d, 11, 3e, 42, 11, 03, 0d, 3b, 15, 11, 3e, 42, 11, 03, 0d, 15, 36, 3b, 15, 11, 3e, 42, 11, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 42, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 3e, 02, 0a, 00, 0b, 3b, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 36, 00, 31, 00, 32, 33, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 47, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 18
+- expression 0 operands: lhs = Counter(0), rhs = Expression(17, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(4), rhs = Expression(15, Sub)
+- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 8 operands: lhs = Expression(14, Add), rhs = Counter(5)
+- expression 9 operands: lhs = Counter(4), rhs = Expression(15, Sub)
+- expression 10 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(5), rhs = Expression(13, Sub)
+- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(5)
+- expression 14 operands: lhs = Counter(4), rhs = Expression(15, Sub)
+- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 17 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 13
+- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24)
+ = (c0 + (c1 + c2))
+- Code(Expression(16, Sub)) at (prev + 1, 12) to (start + 0, 25)
+ = ((c0 + (c1 + c2)) - c3)
+- Code(Counter(4)) at (prev + 0, 26) to (start + 2, 10)
+- Code(Expression(15, Sub)) at (prev + 2, 10) to (start + 0, 11)
+ = (((c0 + (c1 + c2)) - c3) - c4)
+- Code(Expression(14, Add)) at (prev + 2, 12) to (start + 0, 25)
+ = (c4 + (((c0 + (c1 + c2)) - c3) - c4))
+- Code(Counter(5)) at (prev + 0, 26) to (start + 0, 49)
+- Code(Expression(13, Sub)) at (prev + 0, 49) to (start + 0, 50)
+ = ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5)
+- Code(Expression(12, Add)) at (prev + 4, 12) to (start + 0, 25)
+ = (c5 + ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5))
+- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 49)
+- Code(Counter(2)) at (prev + 0, 49) to (start + 0, 50)
+- Code(Expression(17, Add)) at (prev + 1, 9) to (start + 0, 23)
+ = (c1 + c2)
+- Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2)
+
+Function name: abort::might_abort
+Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 24, 02, 02, 0c, 03, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20)
+- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 36)
+- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2)
+ = (c0 - c1)
+
diff --git a/tests/coverage/abort.coverage b/tests/coverage/abort.coverage
new file mode 100644
index 000000000..ceef63867
--- /dev/null
+++ b/tests/coverage/abort.coverage
@@ -0,0 +1,69 @@
+ LL| |#![feature(c_unwind)]
+ LL| |#![allow(unused_assignments)]
+ LL| |
+ LL| 12|extern "C" fn might_abort(should_abort: bool) {
+ LL| 12| if should_abort {
+ LL| 0| println!("aborting...");
+ LL| 0| panic!("panics and aborts");
+ LL| 12| } else {
+ LL| 12| println!("Don't Panic");
+ LL| 12| }
+ LL| 12|}
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| let mut countdown = 10;
+ LL| 11| while countdown > 0 {
+ LL| 10| if countdown < 5 {
+ LL| 4| might_abort(false);
+ LL| 6| }
+ LL| | // See discussion (below the `Notes` section) on coverage results for the closing brace.
+ LL| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line.
+ ^4 ^6
+ LL| | // For the following example, the closing brace is the last character on the line.
+ LL| | // This shows the character after the closing brace is highlighted, even if that next
+ LL| | // character is a newline.
+ LL| 10| if countdown < 5 { might_abort(false); }
+ ^4 ^6
+ LL| 10| countdown -= 1;
+ LL| | }
+ LL| 1| Ok(())
+ LL| 1|}
+ LL| |
+ LL| |// Notes:
+ LL| |// 1. Compare this program and its coverage results to those of the similar tests
+ LL| |// `panic_unwind.rs` and `try_error_result.rs`.
+ LL| |// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`.
+ LL| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage
+ LL| |// results show where the program did and did not execute.
+ LL| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as
+ LL| |// intended"). Coverage results would show no executed coverage regions.
+ LL| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status
+ LL| |// (on Linux at least).
+ LL| |
+ LL| |/*
+ LL| |
+ LL| |Expect the following coverage results:
+ LL| |
+ LL| |```text
+ LL| | 16| 11| while countdown > 0 {
+ LL| | 17| 10| if countdown < 5 {
+ LL| | 18| 4| might_abort(false);
+ LL| | 19| 6| }
+ LL| |```
+ LL| |
+ LL| |This is actually correct.
+ LL| |
+ LL| |The condition `countdown < 5` executed 10 times (10 loop iterations).
+ LL| |
+ LL| |It evaluated to `true` 4 times, and executed the `might_abort()` call.
+ LL| |
+ LL| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit
+ LL| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s
+ LL| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the
+ LL| |non-true condition.
+ LL| |
+ LL| |As another example of why this is important, say the condition was `countdown < 50`, which is always
+ LL| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called.
+ LL| |The closing brace would have a count of `0`, highlighting the missed coverage.
+ LL| |*/
+
diff --git a/tests/coverage/abort.rs b/tests/coverage/abort.rs
new file mode 100644
index 000000000..98264bdc1
--- /dev/null
+++ b/tests/coverage/abort.rs
@@ -0,0 +1,66 @@
+#![feature(c_unwind)]
+#![allow(unused_assignments)]
+
+extern "C" fn might_abort(should_abort: bool) {
+ if should_abort {
+ println!("aborting...");
+ panic!("panics and aborts");
+ } else {
+ println!("Don't Panic");
+ }
+}
+
+fn main() -> Result<(), u8> {
+ let mut countdown = 10;
+ while countdown > 0 {
+ if countdown < 5 {
+ might_abort(false);
+ }
+ // See discussion (below the `Notes` section) on coverage results for the closing brace.
+ if countdown < 5 { might_abort(false); } // Counts for different regions on one line.
+ // For the following example, the closing brace is the last character on the line.
+ // This shows the character after the closing brace is highlighted, even if that next
+ // character is a newline.
+ if countdown < 5 { might_abort(false); }
+ countdown -= 1;
+ }
+ Ok(())
+}
+
+// Notes:
+// 1. Compare this program and its coverage results to those of the similar tests
+// `panic_unwind.rs` and `try_error_result.rs`.
+// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`.
+// 3. The test does not invoke the abort. By executing to a successful completion, the coverage
+// results show where the program did and did not execute.
+// 4. If the program actually aborted, the coverage counters would not be saved (which "works as
+// intended"). Coverage results would show no executed coverage regions.
+// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status
+// (on Linux at least).
+
+/*
+
+Expect the following coverage results:
+
+```text
+ 16| 11| while countdown > 0 {
+ 17| 10| if countdown < 5 {
+ 18| 4| might_abort(false);
+ 19| 6| }
+```
+
+This is actually correct.
+
+The condition `countdown < 5` executed 10 times (10 loop iterations).
+
+It evaluated to `true` 4 times, and executed the `might_abort()` call.
+
+It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit
+`else`, the coverage implementation injects a counter, at the character immediately after the `if`s
+closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the
+non-true condition.
+
+As another example of why this is important, say the condition was `countdown < 50`, which is always
+`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called.
+The closing brace would have a count of `0`, highlighting the missed coverage.
+*/
diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map
new file mode 100644
index 000000000..dd413123d
--- /dev/null
+++ b/tests/coverage/assert.cov-map
@@ -0,0 +1,40 @@
+Function name: assert::main
+Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 8
+- expression 0 operands: lhs = Counter(0), rhs = Expression(6, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(1)
+- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(4)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 9, 1) to (start + 1, 27)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24)
+ = (c0 + (c1 + (c2 + c3)))
+- Code(Expression(5, Sub)) at (prev + 1, 12) to (start + 0, 26)
+ = ((c0 + (c1 + (c2 + c3))) - c4)
+- Code(Counter(1)) at (prev + 0, 27) to (start + 2, 10)
+- Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32)
+ = (((c0 + (c1 + (c2 + c3))) - c4) - c1)
+- Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10)
+- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23)
+ = (c1 + (c2 + c3))
+- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2)
+
+Function name: assert::might_fail_assert
+Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 15)
+- Code(Expression(0, Sub)) at (prev + 2, 37) to (start + 0, 61)
+ = (c0 - c1)
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
+
diff --git a/tests/coverage/assert.coverage b/tests/coverage/assert.coverage
new file mode 100644
index 000000000..8b997724c
--- /dev/null
+++ b/tests/coverage/assert.coverage
@@ -0,0 +1,34 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |// failure-status: 101
+ LL| |
+ LL| 4|fn might_fail_assert(one_plus_one: u32) {
+ LL| 4| println!("does 1 + 1 = {}?", one_plus_one);
+ LL| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong");
+ ^1
+ LL| 3|}
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| let mut countdown = 10;
+ LL| 11| while countdown > 0 {
+ LL| 11| if countdown == 1 {
+ LL| 1| might_fail_assert(3);
+ LL| 10| } else if countdown < 5 {
+ LL| 3| might_fail_assert(2);
+ LL| 6| }
+ LL| 10| countdown -= 1;
+ LL| | }
+ LL| 0| Ok(())
+ LL| 0|}
+ LL| |
+ LL| |// Notes:
+ LL| |// 1. Compare this program and its coverage results to those of the very similar test
+ LL| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`.
+ LL| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or
+ LL| |// related `assert_*!()` macro.
+ LL| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce
+ LL| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to
+ LL| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails).
+ LL| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test
+ LL| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the
+ LL| |// Rust compiler to check for runtime failures, such as numeric overflows.
+
diff --git a/tests/coverage/assert.rs b/tests/coverage/assert.rs
new file mode 100644
index 000000000..85e6662a6
--- /dev/null
+++ b/tests/coverage/assert.rs
@@ -0,0 +1,32 @@
+#![allow(unused_assignments)]
+// failure-status: 101
+
+fn might_fail_assert(one_plus_one: u32) {
+ println!("does 1 + 1 = {}?", one_plus_one);
+ assert_eq!(1 + 1, one_plus_one, "the argument was wrong");
+}
+
+fn main() -> Result<(), u8> {
+ let mut countdown = 10;
+ while countdown > 0 {
+ if countdown == 1 {
+ might_fail_assert(3);
+ } else if countdown < 5 {
+ might_fail_assert(2);
+ }
+ countdown -= 1;
+ }
+ Ok(())
+}
+
+// Notes:
+// 1. Compare this program and its coverage results to those of the very similar test
+// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`.
+// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or
+// related `assert_*!()` macro.
+// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce
+// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to
+// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails).
+// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test
+// (and in many other coverage tests). The `Assert` terminator is typically generated by the
+// Rust compiler to check for runtime failures, such as numeric overflows.
diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map
new file mode 100644
index 000000000..598791537
--- /dev/null
+++ b/tests/coverage/async.cov-map
@@ -0,0 +1,326 @@
+Function name: async::c
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 00, 19]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 25)
+
+Function name: async::c::{closure#0}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 05, 19, 01, 0e, 05, 02, 09, 00, 0a, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 5, 25) to (start + 1, 14)
+- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: async::d
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0d, 01, 00, 14]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 20)
+
+Function name: async::d::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0d, 14, 00, 19]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 13, 20) to (start + 0, 25)
+
+Function name: async::e (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0f, 01, 00, 14]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 15, 1) to (start + 0, 20)
+
+Function name: async::e::{closure#0} (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0f, 14, 00, 19]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 15, 20) to (start + 0, 25)
+
+Function name: async::executor::block_on::<core::pin::Pin<&mut async::i::{closure#0}>>
+Raw bytes (40): 0x[01, 01, 03, 0b, 05, 01, 05, 01, 05, 06, 01, 6e, 05, 0a, 36, 02, 0d, 20, 00, 23, 0b, 00, 27, 00, 49, 02, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 02, 02, 05, 00, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 110, 5) to (start + 10, 54)
+- Code(Expression(0, Sub)) at (prev + 13, 32) to (start + 0, 35)
+ = ((c0 + c1) - c1)
+- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73)
+ = (c0 + c1)
+- Code(Expression(0, Sub)) at (prev + 1, 23) to (start + 0, 26)
+ = ((c0 + c1) - c1)
+- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15)
+- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6)
+ = ((c0 + c1) - c1)
+
+Function name: async::executor::block_on::VTABLE::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 72, 11, 00, 33]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 114, 17) to (start + 0, 51)
+
+Function name: async::executor::block_on::VTABLE::{closure#1}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 73, 11, 00, 33]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 115, 17) to (start + 0, 51)
+
+Function name: async::executor::block_on::VTABLE::{closure#2}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 74, 11, 00, 33]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 116, 17) to (start + 0, 51)
+
+Function name: async::executor::block_on::VTABLE::{closure#3}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 75, 11, 00, 13]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 117, 17) to (start + 0, 19)
+
+Function name: async::f
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 14]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 20)
+
+Function name: async::f::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 14, 00, 19]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 17, 20) to (start + 0, 25)
+
+Function name: async::foo (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 13, 01, 00, 1e]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 19, 1) to (start + 0, 30)
+
+Function name: async::foo::{closure#0} (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 13, 1e, 00, 2d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 19, 30) to (start + 0, 45)
+
+Function name: async::g
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 17]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 23)
+
+Function name: async::g::{closure#0} (unused)
+Raw bytes (69): 0x[01, 01, 00, 0d, 00, 15, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 11, 00, 00, 12, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 13
+- Code(Zero) at (prev + 21, 23) to (start + 1, 12)
+- Code(Zero) at (prev + 2, 9) to (start + 0, 10)
+- Code(Zero) at (prev + 0, 14) to (start + 0, 17)
+- Code(Zero) at (prev + 0, 18) to (start + 0, 23)
+- Code(Zero) at (prev + 0, 27) to (start + 0, 28)
+- Code(Zero) at (prev + 0, 32) to (start + 0, 34)
+- Code(Zero) at (prev + 1, 9) to (start + 0, 10)
+- Code(Zero) at (prev + 0, 14) to (start + 0, 17)
+- Code(Zero) at (prev + 0, 18) to (start + 0, 23)
+- Code(Zero) at (prev + 0, 27) to (start + 0, 28)
+- Code(Zero) at (prev + 0, 32) to (start + 0, 34)
+- Code(Zero) at (prev + 1, 14) to (start + 0, 16)
+- Code(Zero) at (prev + 2, 1) to (start + 0, 2)
+
+Function name: async::h
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 16]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 22)
+
+Function name: async::h::{closure#0} (unused)
+Raw bytes (44): 0x[01, 01, 00, 08, 00, 1d, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 13, 00, 00, 14, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 8
+- Code(Zero) at (prev + 29, 22) to (start + 3, 12)
+- Code(Zero) at (prev + 4, 9) to (start + 0, 10)
+- Code(Zero) at (prev + 0, 14) to (start + 0, 19)
+- Code(Zero) at (prev + 0, 20) to (start + 0, 25)
+- Code(Zero) at (prev + 0, 26) to (start + 0, 27)
+- Code(Zero) at (prev + 0, 32) to (start + 0, 34)
+- Code(Zero) at (prev + 1, 14) to (start + 0, 16)
+- Code(Zero) at (prev + 2, 1) to (start + 0, 2)
+
+Function name: async::i
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 01, 00, 13]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 38, 1) to (start + 0, 19)
+
+Function name: async::i::{closure#0}
+Raw bytes (78): 0x[01, 01, 02, 19, 07, 1d, 21, 0e, 01, 26, 13, 04, 0c, 0d, 05, 09, 00, 0a, 01, 00, 0e, 00, 12, 05, 00, 13, 00, 18, 09, 00, 1c, 00, 21, 0d, 00, 27, 00, 2a, 15, 00, 2b, 00, 30, 1d, 01, 09, 00, 0a, 11, 00, 0e, 00, 11, 25, 00, 12, 00, 17, 29, 00, 1b, 00, 20, 1d, 00, 24, 00, 26, 21, 01, 0e, 00, 10, 03, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(6), rhs = Expression(1, Add)
+- expression 1 operands: lhs = Counter(7), rhs = Counter(8)
+Number of file 0 mappings: 14
+- Code(Counter(0)) at (prev + 38, 19) to (start + 4, 12)
+- Code(Counter(3)) at (prev + 5, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 19) to (start + 0, 24)
+- Code(Counter(2)) at (prev + 0, 28) to (start + 0, 33)
+- Code(Counter(3)) at (prev + 0, 39) to (start + 0, 42)
+- Code(Counter(5)) at (prev + 0, 43) to (start + 0, 48)
+- Code(Counter(7)) at (prev + 1, 9) to (start + 0, 10)
+- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 17)
+- Code(Counter(9)) at (prev + 0, 18) to (start + 0, 23)
+- Code(Counter(10)) at (prev + 0, 27) to (start + 0, 32)
+- Code(Counter(7)) at (prev + 0, 36) to (start + 0, 38)
+- Code(Counter(8)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(0, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = (c6 + (c7 + c8))
+
+Function name: async::j
+Raw bytes (53): 0x[01, 01, 02, 05, 07, 09, 0d, 09, 01, 31, 01, 13, 0c, 05, 14, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 49, 1) to (start + 19, 12)
+- Code(Counter(1)) at (prev + 20, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 27)
+- Code(Counter(1)) at (prev + 0, 31) to (start + 0, 39)
+- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 10)
+- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 26)
+- Code(Counter(2)) at (prev + 0, 30) to (start + 0, 32)
+- Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(0, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = (c1 + (c2 + c3))
+
+Function name: async::j::c
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 33, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 07, 02, 05, 00, 06]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 51, 5) to (start + 1, 18)
+- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14)
+- Code(Expression(0, Sub)) at (prev + 10, 13) to (start + 0, 14)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
+ = (c1 + (c0 - c1))
+
+Function name: async::j::d
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 42, 05, 00, 17]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 66, 5) to (start + 0, 23)
+
+Function name: async::j::f
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 43, 05, 00, 17]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 67, 5) to (start + 0, 23)
+
+Function name: async::k (unused)
+Raw bytes (29): 0x[01, 01, 00, 05, 00, 4b, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 5
+- Code(Zero) at (prev + 75, 1) to (start + 1, 12)
+- Code(Zero) at (prev + 2, 14) to (start + 0, 16)
+- Code(Zero) at (prev + 1, 14) to (start + 0, 16)
+- Code(Zero) at (prev + 1, 14) to (start + 0, 16)
+- Code(Zero) at (prev + 2, 1) to (start + 0, 2)
+
+Function name: async::l
+Raw bytes (37): 0x[01, 01, 04, 01, 07, 09, 05, 09, 0f, 05, 02, 05, 01, 53, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(2), rhs = Expression(3, Add)
+- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 5
+- Code(Counter(0)) at (prev + 83, 1) to (start + 1, 12)
+- Code(Expression(0, Sub)) at (prev + 2, 14) to (start + 0, 16)
+ = (c0 - (c2 + c1))
+- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Counter(2)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = (c2 + (c1 + (c0 - (c2 + c1))))
+
+Function name: async::m
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 01, 00, 19]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 91, 1) to (start + 0, 25)
+
+Function name: async::m::{closure#0} (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 5b, 19, 00, 22]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 91, 25) to (start + 0, 34)
+
+Function name: async::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 5d, 01, 08, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 93, 1) to (start + 8, 2)
+
diff --git a/tests/coverage/async.coverage b/tests/coverage/async.coverage
new file mode 100644
index 000000000..07bc16c2d
--- /dev/null
+++ b/tests/coverage/async.coverage
@@ -0,0 +1,139 @@
+ LL| |#![allow(unused_assignments, dead_code)]
+ LL| |
+ LL| |// compile-flags: --edition=2018 -C opt-level=1
+ LL| |
+ LL| 1|async fn c(x: u8) -> u8 {
+ LL| 1| if x == 8 {
+ LL| 1| 1
+ LL| | } else {
+ LL| 0| 0
+ LL| | }
+ LL| 1|}
+ LL| |
+ LL| 0|async fn d() -> u8 { 1 }
+ LL| |
+ LL| 0|async fn e() -> u8 { 1 } // unused function; executor does not block on `g()`
+ LL| |
+ LL| 1|async fn f() -> u8 { 1 }
+ LL| |
+ LL| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()`
+ LL| |
+ LL| 1|pub async fn g(x: u8) {
+ LL| 0| match x {
+ LL| 0| y if e().await == y => (),
+ LL| 0| y if f().await == y => (),
+ LL| 0| _ => (),
+ LL| | }
+ LL| 0|}
+ LL| |
+ LL| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not
+ LL| 0| // executed (not awaited) so the open brace has a `0` count (at least when
+ LL| 0| // displayed with `llvm-cov show` in color-mode).
+ LL| 0| match x {
+ LL| 0| y if foo().await[y] => (),
+ LL| 0| _ => (),
+ LL| | }
+ LL| 0|}
+ LL| |
+ LL| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions:
+ LL| 1| // (a) the function signature, counted when the function is called; and
+ LL| 1| // (b) the open brace for the function body, counted once when the body is
+ LL| 1| // executed asynchronously.
+ LL| 1| match x {
+ LL| 1| y if c(x).await == y + 1 => { d().await; }
+ ^0 ^0 ^0 ^0
+ LL| 1| y if f().await == y + 1 => (),
+ ^0 ^0 ^0
+ LL| 1| _ => (),
+ LL| | }
+ LL| 1|}
+ LL| |
+ LL| 1|fn j(x: u8) {
+ LL| 1| // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`.
+ LL| 1| fn c(x: u8) -> u8 {
+ LL| 1| if x == 8 {
+ LL| 1| 1 // This line appears covered, but the 1-character expression span covering the `1`
+ ^0
+ LL| 1| // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because
+ LL| 1| // `fn j()` executes the open brace for the function body, followed by the function's
+ LL| 1| // first executable statement, `match x`. Inner function declarations are not
+ LL| 1| // "visible" to the MIR for `j()`, so the code region counts all lines between the
+ LL| 1| // open brace and the first statement as executed, which is, in a sense, true.
+ LL| 1| // `llvm-cov show` overcomes this kind of situation by showing the actual counts
+ LL| 1| // of the enclosed coverages, (that is, the `1` expression was not executed, and
+ LL| 1| // accurately displays a `0`).
+ LL| 1| } else {
+ LL| 1| 0
+ LL| 1| }
+ LL| 1| }
+ LL| 1| fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed
+ ^0
+ LL| 1| fn f() -> u8 { 1 }
+ LL| 1| match x {
+ LL| 1| y if c(x) == y + 1 => { d(); }
+ ^0 ^0
+ LL| 1| y if f() == y + 1 => (),
+ ^0 ^0
+ LL| 1| _ => (),
+ LL| | }
+ LL| 1|}
+ LL| |
+ LL| 0|fn k(x: u8) { // unused function
+ LL| 0| match x {
+ LL| 0| 1 => (),
+ LL| 0| 2 => (),
+ LL| 0| _ => (),
+ LL| | }
+ LL| 0|}
+ LL| |
+ LL| 1|fn l(x: u8) {
+ LL| 1| match x {
+ LL| 0| 1 => (),
+ LL| 0| 2 => (),
+ LL| 1| _ => (),
+ LL| | }
+ LL| 1|}
+ LL| |
+ LL| 1|async fn m(x: u8) -> u8 { x - 1 }
+ ^0
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let _ = g(10);
+ LL| 1| let _ = h(9);
+ LL| 1| let mut future = Box::pin(i(8));
+ LL| 1| j(7);
+ LL| 1| l(6);
+ LL| 1| let _ = m(5);
+ LL| 1| executor::block_on(future.as_mut());
+ LL| 1|}
+ LL| |
+ LL| |mod executor {
+ LL| | use core::{
+ LL| | future::Future,
+ LL| | pin::Pin,
+ LL| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ LL| | };
+ LL| |
+ LL| 1| pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ LL| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ LL| 1| use std::hint::unreachable_unchecked;
+ LL| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ LL| 1| |_| unsafe { unreachable_unchecked() }, // clone
+ ^0
+ LL| 1| |_| unsafe { unreachable_unchecked() }, // wake
+ ^0
+ LL| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ ^0
+ LL| 1| |_| (),
+ LL| 1| );
+ LL| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ LL| 1| let mut context = Context::from_waker(&waker);
+ LL| |
+ LL| | loop {
+ LL| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ LL| 1| break val;
+ LL| 0| }
+ LL| | }
+ LL| 1| }
+ LL| |}
+
diff --git a/tests/coverage/async.rs b/tests/coverage/async.rs
new file mode 100644
index 000000000..efd9e62d6
--- /dev/null
+++ b/tests/coverage/async.rs
@@ -0,0 +1,128 @@
+#![allow(unused_assignments, dead_code)]
+
+// compile-flags: --edition=2018 -C opt-level=1
+
+async fn c(x: u8) -> u8 {
+ if x == 8 {
+ 1
+ } else {
+ 0
+ }
+}
+
+async fn d() -> u8 { 1 }
+
+async fn e() -> u8 { 1 } // unused function; executor does not block on `g()`
+
+async fn f() -> u8 { 1 }
+
+async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()`
+
+pub async fn g(x: u8) {
+ match x {
+ y if e().await == y => (),
+ y if f().await == y => (),
+ _ => (),
+ }
+}
+
+async fn h(x: usize) { // The function signature is counted when called, but the body is not
+ // executed (not awaited) so the open brace has a `0` count (at least when
+ // displayed with `llvm-cov show` in color-mode).
+ match x {
+ y if foo().await[y] => (),
+ _ => (),
+ }
+}
+
+async fn i(x: u8) { // line coverage is 1, but there are 2 regions:
+ // (a) the function signature, counted when the function is called; and
+ // (b) the open brace for the function body, counted once when the body is
+ // executed asynchronously.
+ match x {
+ y if c(x).await == y + 1 => { d().await; }
+ y if f().await == y + 1 => (),
+ _ => (),
+ }
+}
+
+fn j(x: u8) {
+ // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`.
+ fn c(x: u8) -> u8 {
+ if x == 8 {
+ 1 // This line appears covered, but the 1-character expression span covering the `1`
+ // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because
+ // `fn j()` executes the open brace for the function body, followed by the function's
+ // first executable statement, `match x`. Inner function declarations are not
+ // "visible" to the MIR for `j()`, so the code region counts all lines between the
+ // open brace and the first statement as executed, which is, in a sense, true.
+ // `llvm-cov show` overcomes this kind of situation by showing the actual counts
+ // of the enclosed coverages, (that is, the `1` expression was not executed, and
+ // accurately displays a `0`).
+ } else {
+ 0
+ }
+ }
+ fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed
+ fn f() -> u8 { 1 }
+ match x {
+ y if c(x) == y + 1 => { d(); }
+ y if f() == y + 1 => (),
+ _ => (),
+ }
+}
+
+fn k(x: u8) { // unused function
+ match x {
+ 1 => (),
+ 2 => (),
+ _ => (),
+ }
+}
+
+fn l(x: u8) {
+ match x {
+ 1 => (),
+ 2 => (),
+ _ => (),
+ }
+}
+
+async fn m(x: u8) -> u8 { x - 1 }
+
+fn main() {
+ let _ = g(10);
+ let _ = h(9);
+ let mut future = Box::pin(i(8));
+ j(7);
+ l(6);
+ let _ = m(5);
+ executor::block_on(future.as_mut());
+}
+
+mod executor {
+ use core::{
+ future::Future,
+ pin::Pin,
+ task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ };
+
+ pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ use std::hint::unreachable_unchecked;
+ static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ |_| unsafe { unreachable_unchecked() }, // clone
+ |_| unsafe { unreachable_unchecked() }, // wake
+ |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ |_| (),
+ );
+ let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ let mut context = Context::from_waker(&waker);
+
+ loop {
+ if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ break val;
+ }
+ }
+ }
+}
diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map
new file mode 100644
index 000000000..cc7aed9ae
--- /dev/null
+++ b/tests/coverage/async2.cov-map
@@ -0,0 +1,132 @@
+Function name: async2::async_func
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 17]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 23)
+
+Function name: async2::async_func::{closure#0}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 17, 03, 09, 05, 03, 0a, 02, 06, 02, 02, 06, 00, 07, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 11, 23) to (start + 3, 9)
+- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: async2::async_func_just_println
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 24]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 36)
+
+Function name: async2::async_func_just_println::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 24, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 19, 36) to (start + 2, 2)
+
+Function name: async2::executor::block_on::<async2::async_func::{closure#0}>
+Raw bytes (40): 0x[01, 01, 03, 0b, 05, 01, 05, 01, 05, 06, 01, 27, 05, 0a, 36, 02, 0d, 20, 00, 23, 0b, 00, 27, 00, 49, 02, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 02, 02, 05, 00, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 39, 5) to (start + 10, 54)
+- Code(Expression(0, Sub)) at (prev + 13, 32) to (start + 0, 35)
+ = ((c0 + c1) - c1)
+- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73)
+ = (c0 + c1)
+- Code(Expression(0, Sub)) at (prev + 1, 23) to (start + 0, 26)
+ = ((c0 + c1) - c1)
+- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15)
+- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6)
+ = ((c0 + c1) - c1)
+
+Function name: async2::executor::block_on::<async2::async_func_just_println::{closure#0}>
+Raw bytes (40): 0x[01, 01, 03, 0b, 05, 01, 05, 01, 05, 06, 01, 27, 05, 0a, 36, 02, 0d, 20, 00, 23, 0b, 00, 27, 00, 49, 02, 01, 17, 00, 1a, 05, 01, 0e, 00, 0f, 02, 02, 05, 00, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Expression(2, Add), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 39, 5) to (start + 10, 54)
+- Code(Expression(0, Sub)) at (prev + 13, 32) to (start + 0, 35)
+ = ((c0 + c1) - c1)
+- Code(Expression(2, Add)) at (prev + 0, 39) to (start + 0, 73)
+ = (c0 + c1)
+- Code(Expression(0, Sub)) at (prev + 1, 23) to (start + 0, 26)
+ = ((c0 + c1) - c1)
+- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 15)
+- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6)
+ = ((c0 + c1) - c1)
+
+Function name: async2::executor::block_on::VTABLE::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 2b, 11, 00, 33]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 43, 17) to (start + 0, 51)
+
+Function name: async2::executor::block_on::VTABLE::{closure#1}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 11, 00, 33]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 44, 17) to (start + 0, 51)
+
+Function name: async2::executor::block_on::VTABLE::{closure#2}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 2d, 11, 00, 33]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 45, 17) to (start + 0, 51)
+
+Function name: async2::executor::block_on::VTABLE::{closure#3}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 2e, 11, 00, 13]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 46, 17) to (start + 0, 19)
+
+Function name: async2::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 07, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 23, 1) to (start + 7, 2)
+
+Function name: async2::non_async_func
+Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 03, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 3, 1) to (start + 3, 9)
+- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + Zero)
+
diff --git a/tests/coverage/async2.coverage b/tests/coverage/async2.coverage
new file mode 100644
index 000000000..fcb0a3aed
--- /dev/null
+++ b/tests/coverage/async2.coverage
@@ -0,0 +1,104 @@
+ LL| |// compile-flags: --edition=2018
+ LL| |
+ LL| 1|fn non_async_func() {
+ LL| 1| println!("non_async_func was covered");
+ LL| 1| let b = true;
+ LL| 1| if b {
+ LL| 1| println!("non_async_func println in block");
+ LL| 1| }
+ ^0
+ LL| 1|}
+ LL| |
+ LL| 1|async fn async_func() {
+ LL| 1| println!("async_func was covered");
+ LL| 1| let b = true;
+ LL| 1| if b {
+ LL| 1| println!("async_func println in block");
+ LL| 1| }
+ ^0
+ LL| 1|}
+ LL| |
+ LL| 1|async fn async_func_just_println() {
+ LL| 1| println!("async_func_just_println was covered");
+ LL| 1|}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| println!("codecovsample::main");
+ LL| 1|
+ LL| 1| non_async_func();
+ LL| 1|
+ LL| 1| executor::block_on(async_func());
+ LL| 1| executor::block_on(async_func_just_println());
+ LL| 1|}
+ LL| |
+ LL| |mod executor {
+ LL| | use core::{
+ LL| | future::Future,
+ LL| | pin::Pin,
+ LL| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ LL| | };
+ LL| |
+ LL| 2| pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ LL| 2| let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ LL| 2| use std::hint::unreachable_unchecked;
+ LL| 2| static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ LL| 2| |_| unsafe { unreachable_unchecked() }, // clone
+ ^0
+ LL| 2| |_| unsafe { unreachable_unchecked() }, // wake
+ ^0
+ LL| 2| |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ ^0
+ LL| 2| |_| (),
+ LL| 2| );
+ LL| 2| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ LL| 2| let mut context = Context::from_waker(&waker);
+ LL| |
+ LL| | loop {
+ LL| 2| if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ LL| 2| break val;
+ LL| 0| }
+ LL| | }
+ LL| 2| }
+ ------------------
+ | async2::executor::block_on::<async2::async_func::{closure#0}>:
+ | LL| 1| pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ | LL| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ | LL| 1| use std::hint::unreachable_unchecked;
+ | LL| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ | LL| 1| |_| unsafe { unreachable_unchecked() }, // clone
+ | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake
+ | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ | LL| 1| |_| (),
+ | LL| 1| );
+ | LL| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ | LL| 1| let mut context = Context::from_waker(&waker);
+ | LL| |
+ | LL| | loop {
+ | LL| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ | LL| 1| break val;
+ | LL| 0| }
+ | LL| | }
+ | LL| 1| }
+ ------------------
+ | async2::executor::block_on::<async2::async_func_just_println::{closure#0}>:
+ | LL| 1| pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ | LL| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ | LL| 1| use std::hint::unreachable_unchecked;
+ | LL| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ | LL| 1| |_| unsafe { unreachable_unchecked() }, // clone
+ | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake
+ | LL| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ | LL| 1| |_| (),
+ | LL| 1| );
+ | LL| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ | LL| 1| let mut context = Context::from_waker(&waker);
+ | LL| |
+ | LL| | loop {
+ | LL| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ | LL| 1| break val;
+ | LL| 0| }
+ | LL| | }
+ | LL| 1| }
+ ------------------
+ LL| |}
+
diff --git a/tests/coverage/async2.rs b/tests/coverage/async2.rs
new file mode 100644
index 000000000..2884ff297
--- /dev/null
+++ b/tests/coverage/async2.rs
@@ -0,0 +1,57 @@
+// compile-flags: --edition=2018
+
+fn non_async_func() {
+ println!("non_async_func was covered");
+ let b = true;
+ if b {
+ println!("non_async_func println in block");
+ }
+}
+
+async fn async_func() {
+ println!("async_func was covered");
+ let b = true;
+ if b {
+ println!("async_func println in block");
+ }
+}
+
+async fn async_func_just_println() {
+ println!("async_func_just_println was covered");
+}
+
+fn main() {
+ println!("codecovsample::main");
+
+ non_async_func();
+
+ executor::block_on(async_func());
+ executor::block_on(async_func_just_println());
+}
+
+mod executor {
+ use core::{
+ future::Future,
+ pin::Pin,
+ task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ };
+
+ pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ use std::hint::unreachable_unchecked;
+ static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ |_| unsafe { unreachable_unchecked() }, // clone
+ |_| unsafe { unreachable_unchecked() }, // wake
+ |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ |_| (),
+ );
+ let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ let mut context = Context::from_waker(&waker);
+
+ loop {
+ if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ break val;
+ }
+ }
+ }
+}
diff --git a/tests/coverage/auxiliary/inline_always_with_dead_code.rs b/tests/coverage/auxiliary/inline_always_with_dead_code.rs
new file mode 100644
index 000000000..9dc50dae2
--- /dev/null
+++ b/tests/coverage/auxiliary/inline_always_with_dead_code.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0
+
+#![allow(dead_code)]
+
+mod foo {
+ #[inline(always)]
+ pub fn called() {}
+
+ fn uncalled() {}
+}
+
+pub mod bar {
+ pub fn call_me() {
+ super::foo::called();
+ }
+}
+
+pub mod baz {
+ pub fn call_me() {
+ super::foo::called();
+ }
+}
diff --git a/tests/coverage/auxiliary/macro_name_span_helper.rs b/tests/coverage/auxiliary/macro_name_span_helper.rs
new file mode 100644
index 000000000..6797c081d
--- /dev/null
+++ b/tests/coverage/auxiliary/macro_name_span_helper.rs
@@ -0,0 +1,10 @@
+// edition: 2021
+
+#[macro_export]
+macro_rules! macro_that_defines_a_function {
+ (fn $name:ident () $body:tt) => {
+ fn $name () -> () $body
+ }
+}
+
+// Non-executable comment.
diff --git a/tests/coverage/auxiliary/unused_mod_helper.rs b/tests/coverage/auxiliary/unused_mod_helper.rs
new file mode 100644
index 000000000..88c5dac65
--- /dev/null
+++ b/tests/coverage/auxiliary/unused_mod_helper.rs
@@ -0,0 +1,4 @@
+#[allow(dead_code)]
+pub fn never_called_function() {
+ println!("I am never called");
+}
diff --git a/tests/coverage/auxiliary/used_crate.rs b/tests/coverage/auxiliary/used_crate.rs
new file mode 100644
index 000000000..c086ef21e
--- /dev/null
+++ b/tests/coverage/auxiliary/used_crate.rs
@@ -0,0 +1,103 @@
+#![allow(unused_assignments, unused_variables)]
+// Verify that coverage works with optimizations:
+// compile-flags: -C opt-level=3
+
+use std::fmt::Debug;
+
+pub fn used_function() {
+ // 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 countdown = 0;
+ if is_true {
+ countdown = 10;
+ }
+ use_this_lib_crate();
+}
+
+pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+}
+// Expect for above function: `Unexecuted instantiation` (see below)
+pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+}
+
+pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+}
+
+pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+}
+
+pub fn unused_generic_function<T: Debug>(arg: T) {
+ println!("unused_generic_function with {:?}", arg);
+}
+
+pub fn unused_function() {
+ let is_true = std::env::args().len() == 1;
+ let mut countdown = 2;
+ if !is_true {
+ countdown = 20;
+ }
+}
+
+#[allow(dead_code)]
+fn unused_private_function() {
+ let is_true = std::env::args().len() == 1;
+ let mut countdown = 2;
+ if !is_true {
+ countdown = 20;
+ }
+}
+
+fn use_this_lib_crate() {
+ used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs");
+ used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
+ "used from library used_crate.rs",
+ );
+ let some_vec = vec![5, 6, 7, 8];
+ used_only_from_this_lib_crate_generic_function(some_vec);
+ used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs");
+}
+
+// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results,
+// for example:
+//
+// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
+//
+// These notices appear when `llvm-cov` shows instantiations. This may be a
+// default option, but it can be suppressed with:
+//
+// ```shell
+// $ `llvm-cov show --show-instantiations=0 ...`
+// ```
+//
+// The notice is triggered because the function is unused by the library itself,
+// and when the library is compiled, a synthetic function is generated, so
+// unused function coverage can be reported. Coverage can be skipped for unused
+// generic functions with:
+//
+// ```shell
+// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...`
+// ```
+//
+// Even though this function is used by `uses_crate.rs` (and
+// counted), with substitutions for `T`, those instantiations are only generated
+// when the generic function is actually used (from the binary, not from this
+// library crate). So the test result shows coverage for all instantiated
+// versions and their generic type substitutions, plus the `Unexecuted
+// instantiation` message for the non-substituted version. This is valid, but
+// unfortunately a little confusing.
+//
+// The library crate has its own coverage map, and the only way to show unused
+// coverage of a generic function is to include the generic function in the
+// coverage map, marked as an "unused function". If the library were used by
+// another binary that never used this generic function, then it would be valid
+// to show the unused generic, with unknown substitution (`_`).
+//
+// The alternative is to exclude all generics from being included in the "unused
+// functions" list, which would then omit coverage results for
+// `unused_generic_function<T>()`, below.
diff --git a/tests/coverage/auxiliary/used_inline_crate.rs b/tests/coverage/auxiliary/used_inline_crate.rs
new file mode 100644
index 000000000..e8929de6b
--- /dev/null
+++ b/tests/coverage/auxiliary/used_inline_crate.rs
@@ -0,0 +1,85 @@
+#![allow(unused_assignments, unused_variables)]
+// Verify that coverage works with optimizations:
+// compile-flags: -C opt-level=3
+
+use std::fmt::Debug;
+
+pub fn used_function() {
+ // 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 countdown = 0;
+ if is_true {
+ countdown = 10;
+ }
+ use_this_lib_crate();
+}
+
+#[inline(always)]
+pub fn used_inline_function() {
+ // 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 countdown = 0;
+ if is_true {
+ countdown = 10;
+ }
+ use_this_lib_crate();
+}
+
+#[inline(always)]
+pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+}
+// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
+
+#[inline(always)]
+pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+}
+
+#[inline(always)]
+pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+}
+
+#[inline(always)]
+pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+}
+
+#[inline(always)]
+pub fn unused_generic_function<T: Debug>(arg: T) {
+ println!("unused_generic_function with {:?}", arg);
+}
+
+#[inline(always)]
+pub fn unused_function() {
+ let is_true = std::env::args().len() == 1;
+ let mut countdown = 2;
+ if !is_true {
+ countdown = 20;
+ }
+}
+
+#[inline(always)]
+#[allow(dead_code)]
+fn unused_private_function() {
+ let is_true = std::env::args().len() == 1;
+ let mut countdown = 2;
+ if !is_true {
+ countdown = 20;
+ }
+}
+
+fn use_this_lib_crate() {
+ used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs");
+ used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
+ "used from library used_crate.rs",
+ );
+ let some_vec = vec![5, 6, 7, 8];
+ used_only_from_this_lib_crate_generic_function(some_vec);
+ used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs");
+}
diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map
new file mode 100644
index 000000000..0b8081acf
--- /dev/null
+++ b/tests/coverage/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/bad_counter_ids.coverage b/tests/coverage/bad_counter_ids.coverage
new file mode 100644
index 000000000..d69ebf160
--- /dev/null
+++ b/tests/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/coverage/bad_counter_ids.rs b/tests/coverage/bad_counter_ids.rs
new file mode 100644
index 000000000..ef5460102
--- /dev/null
+++ b/tests/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());
+}
diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map
new file mode 100644
index 000000000..522c1e73a
--- /dev/null
+++ b/tests/coverage/closure.cov-map
@@ -0,0 +1,275 @@
+Function name: closure::main
+Raw bytes (128): 0x[01, 01, 02, 01, 05, 05, 02, 18, 01, 08, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 07, 01, 05, 03, 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)
+Number of file 0 mappings: 24
+- Code(Counter(0)) at (prev + 8, 1) to (start + 15, 13)
+- Code(Counter(0)) at (prev + 22, 14) to (start + 6, 10)
+- Code(Counter(0)) at (prev + 16, 5) to (start + 19, 13)
+- Code(Counter(0)) at (prev + 26, 14) to (start + 6, 10)
+- Code(Counter(0)) at (prev + 16, 5) to (start + 12, 22)
+- Code(Counter(0)) at (prev + 22, 5) to (start + 13, 24)
+- Code(Counter(0)) at (prev + 25, 9) to (start + 1, 30)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 41)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 45)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 36)
+- Code(Counter(0)) at (prev + 5, 9) to (start + 0, 36)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 33)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 33)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 40)
+- Code(Counter(0)) at (prev + 9, 9) to (start + 0, 50)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 51)
+- Code(Counter(0)) at (prev + 7, 9) to (start + 0, 75)
+- Code(Counter(0)) at (prev + 8, 9) to (start + 0, 72)
+- Code(Counter(0)) at (prev + 10, 9) to (start + 0, 71)
+- Code(Counter(0)) at (prev + 8, 9) to (start + 0, 68)
+- Code(Counter(0)) at (prev + 10, 8) to (start + 0, 16)
+- Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6)
+- Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 3, 2)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#0}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 27, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 39, 5) to (start + 2, 20)
+- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
+- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#10} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, 9a, 01, 07, 00, 21]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 154, 7) to (start + 0, 33)
+
+Function name: closure::main::{closure#11} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, 9e, 01, 07, 00, 21]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 158, 7) to (start + 0, 33)
+
+Function name: closure::main::{closure#12} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, a6, 01, 01, 00, 17]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 166, 1) to (start + 0, 23)
+
+Function name: closure::main::{closure#13} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, ab, 01, 0d, 02, 0e]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 171, 13) to (start + 2, 14)
+
+Function name: closure::main::{closure#14}
+Raw bytes (36): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 05, 03, b2, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 01, 0d, 00, 0e]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 5
+- Code(Expression(0, Add)) at (prev + 178, 13) to (start + 0, 21)
+ = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
+- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
+- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+ = (c0 - c1)
+- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 14)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#15}
+Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, ba, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 186, 9) to (start + 0, 10)
+- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21)
+ = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
+- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
+- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+ = (c0 - c1)
+- Code(Expression(0, Add)) at (prev + 2, 9) to (start + 0, 10)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#16}
+Raw bytes (36): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 05, 03, c4, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 01, 0d, 00, 0e]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 5
+- Code(Expression(0, Add)) at (prev + 196, 13) to (start + 0, 21)
+ = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
+- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
+- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+ = (c0 - c1)
+- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 14)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#17}
+Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, cc, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 204, 9) to (start + 0, 10)
+- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21)
+ = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
+- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
+- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+ = (c0 - c1)
+- Code(Expression(0, Add)) at (prev + 2, 9) to (start + 0, 10)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#18}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 18, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 24, 13) to (start + 2, 28)
+- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18)
+- Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 17) to (start + 1, 14)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#19}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 42, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 66, 13) to (start + 2, 28)
+- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18)
+- Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 17) to (start + 1, 14)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#1}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 51, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 81, 5) to (start + 2, 20)
+- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
+- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#2}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 67, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 103, 5) to (start + 2, 20)
+- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
+- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6)
+ = (c1 + (c0 - c1))
+
+Function name: closure::main::{closure#3} (unused)
+Raw bytes (25): 0x[01, 01, 00, 04, 00, 80, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Zero) at (prev + 128, 5) to (start + 1, 20)
+- Code(Zero) at (prev + 1, 21) to (start + 2, 10)
+- Code(Zero) at (prev + 2, 10) to (start + 0, 11)
+- Code(Zero) at (prev + 1, 9) to (start + 1, 6)
+
+Function name: closure::main::{closure#4} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, 88, 01, 35, 00, 43]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 136, 53) to (start + 0, 67)
+
+Function name: closure::main::{closure#5}
+Raw bytes (10): 0x[01, 01, 00, 01, 01, 8b, 01, 3d, 00, 4f]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 139, 61) to (start + 0, 79)
+
+Function name: closure::main::{closure#6}
+Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 41, 00, 57]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 140, 65) to (start + 0, 87)
+
+Function name: closure::main::{closure#7} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, 8d, 01, 3b, 00, 51]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 141, 59) to (start + 0, 81)
+
+Function name: closure::main::{closure#8} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, 92, 01, 3b, 00, 55]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 146, 59) to (start + 0, 85)
+
+Function name: closure::main::{closure#9} (unused)
+Raw bytes (10): 0x[01, 01, 00, 01, 00, 94, 01, 38, 02, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 148, 56) to (start + 2, 6)
+
diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage
new file mode 100644
index 000000000..67014f792
--- /dev/null
+++ b/tests/coverage/closure.coverage
@@ -0,0 +1,227 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |// compile-flags: -C opt-level=2
+ LL| |
+ LL| |// This test used to be sensitive to certain coverage-specific hacks in
+ LL| |// `rustc_middle/mir/mono.rs`, but those hacks were later cleaned up by
+ LL| |// <https://github.com/rust-lang/rust/pull/83666>.
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1| let is_false = !is_true;
+ LL| 1|
+ LL| 1| let mut some_string = Some(String::from("the string content"));
+ LL| 1| println!(
+ LL| 1| "The string or alt: {}"
+ LL| 1| ,
+ LL| 1| some_string
+ LL| 1| .
+ LL| 1| unwrap_or_else
+ LL| 1| (
+ LL| 1| ||
+ LL| 0| {
+ LL| 0| let mut countdown = 0;
+ LL| 0| if is_false {
+ LL| 0| countdown = 10;
+ LL| 0| }
+ LL| 0| "alt string 1".to_owned()
+ LL| 1| }
+ LL| 1| )
+ LL| 1| );
+ LL| 1|
+ LL| 1| some_string = Some(String::from("the string content"));
+ LL| 1| let
+ LL| 1| a
+ LL| | =
+ LL| | ||
+ LL| 0| {
+ LL| 0| let mut countdown = 0;
+ LL| 0| if is_false {
+ LL| 0| countdown = 10;
+ LL| 0| }
+ LL| 0| "alt string 2".to_owned()
+ LL| 0| };
+ LL| 1| println!(
+ LL| 1| "The string or alt: {}"
+ LL| 1| ,
+ LL| 1| some_string
+ LL| 1| .
+ LL| 1| unwrap_or_else
+ LL| 1| (
+ LL| 1| a
+ LL| 1| )
+ LL| 1| );
+ LL| 1|
+ LL| 1| some_string = None;
+ LL| 1| println!(
+ LL| 1| "The string or alt: {}"
+ LL| 1| ,
+ LL| 1| some_string
+ LL| 1| .
+ LL| 1| unwrap_or_else
+ LL| 1| (
+ LL| 1| ||
+ LL| 1| {
+ LL| 1| let mut countdown = 0;
+ LL| 1| if is_false {
+ LL| 0| countdown = 10;
+ LL| 1| }
+ LL| 1| "alt string 3".to_owned()
+ LL| 1| }
+ LL| 1| )
+ LL| 1| );
+ LL| 1|
+ LL| 1| some_string = None;
+ LL| 1| let
+ LL| 1| a
+ LL| | =
+ LL| | ||
+ LL| 1| {
+ LL| 1| let mut countdown = 0;
+ LL| 1| if is_false {
+ LL| 0| countdown = 10;
+ LL| 1| }
+ LL| 1| "alt string 4".to_owned()
+ LL| 1| };
+ LL| 1| println!(
+ LL| 1| "The string or alt: {}"
+ LL| 1| ,
+ LL| 1| some_string
+ LL| 1| .
+ LL| 1| unwrap_or_else
+ LL| 1| (
+ LL| 1| a
+ LL| 1| )
+ LL| 1| );
+ LL| 1|
+ LL| 1| let
+ LL| 1| quote_closure
+ LL| | =
+ LL| | |val|
+ LL| 5| {
+ LL| 5| let mut countdown = 0;
+ LL| 5| if is_false {
+ LL| 0| countdown = 10;
+ LL| 5| }
+ LL| 5| format!("'{}'", val)
+ LL| 5| };
+ LL| 1| println!(
+ LL| 1| "Repeated, quoted string: {:?}"
+ LL| 1| ,
+ LL| 1| std::iter::repeat("repeat me")
+ LL| 1| .take(5)
+ LL| 1| .map
+ LL| 1| (
+ LL| 1| quote_closure
+ LL| 1| )
+ LL| 1| .collect::<Vec<_>>()
+ LL| 1| );
+ LL| 1|
+ LL| 1| let
+ LL| 1| _unused_closure
+ LL| | =
+ LL| | |
+ LL| | mut countdown
+ LL| | |
+ LL| 0| {
+ LL| 0| if is_false {
+ LL| 0| countdown = 10;
+ LL| 0| }
+ LL| 0| "closure should be unused".to_owned()
+ LL| 0| };
+ LL| |
+ LL| 1| let mut countdown = 10;
+ LL| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
+ ^0
+ LL| |
+ LL| |
+ LL| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called");
+ LL| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called");
+ ^0
+ LL| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called");
+ ^0
+ LL| |
+ LL| |
+ LL| |
+ LL| |
+ LL| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") };
+ ^0
+ LL| |
+ LL| 1| let _shortish_unused_closure = | _unused_arg: u8 | {
+ LL| 0| println!("not called")
+ LL| 0| };
+ LL| |
+ LL| 1| let _as_short_unused_closure = |
+ LL| | _unused_arg: u8
+ LL| 0| | { println!("not called") };
+ LL| |
+ LL| 1| let _almost_as_short_unused_closure = |
+ LL| | _unused_arg: u8
+ LL| 0| | { println!("not called") }
+ LL| | ;
+ LL| |
+ LL| |
+ LL| |
+ LL| |
+ LL| |
+ LL| 1| let _short_unused_closure_line_break_no_block = | _unused_arg: u8 |
+ LL| 0|println!("not called")
+ LL| | ;
+ LL| |
+ LL| 1| let _short_unused_closure_line_break_no_block2 =
+ LL| | | _unused_arg: u8 |
+ LL| 0| println!(
+ LL| 0| "not called"
+ LL| 0| )
+ LL| | ;
+ LL| |
+ LL| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch =
+ LL| | | _unused_arg: u8 |
+ LL| 0| println!(
+ LL| 0| "not called: {}",
+ LL| 0| if is_true { "check" } else { "me" }
+ LL| 0| )
+ LL| | ;
+ LL| |
+ LL| 1| let short_used_not_covered_closure_line_break_block_embedded_branch =
+ LL| | | _unused_arg: u8 |
+ LL| 0| {
+ LL| 0| println!(
+ LL| 0| "not called: {}",
+ LL| 0| if is_true { "check" } else { "me" }
+ LL| | )
+ LL| 0| }
+ LL| | ;
+ LL| |
+ LL| 1| let short_used_covered_closure_line_break_no_block_embedded_branch =
+ LL| | | _unused_arg: u8 |
+ LL| 1| println!(
+ LL| 1| "not called: {}",
+ LL| 1| if is_true { "check" } else { "me" }
+ ^0
+ LL| 1| )
+ LL| | ;
+ LL| |
+ LL| 1| let short_used_covered_closure_line_break_block_embedded_branch =
+ LL| | | _unused_arg: u8 |
+ LL| 1| {
+ LL| 1| println!(
+ LL| 1| "not called: {}",
+ LL| 1| if is_true { "check" } else { "me" }
+ ^0
+ LL| | )
+ LL| 1| }
+ LL| | ;
+ LL| |
+ LL| 1| if is_false {
+ LL| 0| short_used_not_covered_closure_macro(0);
+ LL| 0| short_used_not_covered_closure_line_break_no_block_embedded_branch(0);
+ LL| 0| short_used_not_covered_closure_line_break_block_embedded_branch(0);
+ LL| 1| }
+ LL| 1| short_used_covered_closure_macro(0);
+ LL| 1| short_used_covered_closure_line_break_no_block_embedded_branch(0);
+ LL| 1| short_used_covered_closure_line_break_block_embedded_branch(0);
+ LL| 1|}
+
diff --git a/tests/coverage/closure.rs b/tests/coverage/closure.rs
new file mode 100644
index 000000000..16a2c4e33
--- /dev/null
+++ b/tests/coverage/closure.rs
@@ -0,0 +1,220 @@
+#![allow(unused_assignments, unused_variables)]
+// compile-flags: -C opt-level=2
+
+// This test used to be sensitive to certain coverage-specific hacks in
+// `rustc_middle/mir/mono.rs`, but those hacks were later cleaned up by
+// <https://github.com/rust-lang/rust/pull/83666>.
+
+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 is_false = !is_true;
+
+ let mut some_string = Some(String::from("the string content"));
+ println!(
+ "The string or alt: {}"
+ ,
+ some_string
+ .
+ unwrap_or_else
+ (
+ ||
+ {
+ let mut countdown = 0;
+ if is_false {
+ countdown = 10;
+ }
+ "alt string 1".to_owned()
+ }
+ )
+ );
+
+ some_string = Some(String::from("the string content"));
+ let
+ a
+ =
+ ||
+ {
+ let mut countdown = 0;
+ if is_false {
+ countdown = 10;
+ }
+ "alt string 2".to_owned()
+ };
+ println!(
+ "The string or alt: {}"
+ ,
+ some_string
+ .
+ unwrap_or_else
+ (
+ a
+ )
+ );
+
+ some_string = None;
+ println!(
+ "The string or alt: {}"
+ ,
+ some_string
+ .
+ unwrap_or_else
+ (
+ ||
+ {
+ let mut countdown = 0;
+ if is_false {
+ countdown = 10;
+ }
+ "alt string 3".to_owned()
+ }
+ )
+ );
+
+ some_string = None;
+ let
+ a
+ =
+ ||
+ {
+ let mut countdown = 0;
+ if is_false {
+ countdown = 10;
+ }
+ "alt string 4".to_owned()
+ };
+ println!(
+ "The string or alt: {}"
+ ,
+ some_string
+ .
+ unwrap_or_else
+ (
+ a
+ )
+ );
+
+ let
+ quote_closure
+ =
+ |val|
+ {
+ let mut countdown = 0;
+ if is_false {
+ countdown = 10;
+ }
+ format!("'{}'", val)
+ };
+ println!(
+ "Repeated, quoted string: {:?}"
+ ,
+ std::iter::repeat("repeat me")
+ .take(5)
+ .map
+ (
+ quote_closure
+ )
+ .collect::<Vec<_>>()
+ );
+
+ let
+ _unused_closure
+ =
+ |
+ mut countdown
+ |
+ {
+ if is_false {
+ countdown = 10;
+ }
+ "closure should be unused".to_owned()
+ };
+
+ let mut countdown = 10;
+ let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
+
+
+ let short_used_covered_closure_macro = | used_arg: u8 | println!("called");
+ let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called");
+ let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called");
+
+
+
+
+ let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") };
+
+ let _shortish_unused_closure = | _unused_arg: u8 | {
+ println!("not called")
+ };
+
+ let _as_short_unused_closure = |
+ _unused_arg: u8
+ | { println!("not called") };
+
+ let _almost_as_short_unused_closure = |
+ _unused_arg: u8
+ | { println!("not called") }
+ ;
+
+
+
+
+
+ let _short_unused_closure_line_break_no_block = | _unused_arg: u8 |
+println!("not called")
+ ;
+
+ let _short_unused_closure_line_break_no_block2 =
+ | _unused_arg: u8 |
+ println!(
+ "not called"
+ )
+ ;
+
+ let short_used_not_covered_closure_line_break_no_block_embedded_branch =
+ | _unused_arg: u8 |
+ println!(
+ "not called: {}",
+ if is_true { "check" } else { "me" }
+ )
+ ;
+
+ let short_used_not_covered_closure_line_break_block_embedded_branch =
+ | _unused_arg: u8 |
+ {
+ println!(
+ "not called: {}",
+ if is_true { "check" } else { "me" }
+ )
+ }
+ ;
+
+ let short_used_covered_closure_line_break_no_block_embedded_branch =
+ | _unused_arg: u8 |
+ println!(
+ "not called: {}",
+ if is_true { "check" } else { "me" }
+ )
+ ;
+
+ let short_used_covered_closure_line_break_block_embedded_branch =
+ | _unused_arg: u8 |
+ {
+ println!(
+ "not called: {}",
+ if is_true { "check" } else { "me" }
+ )
+ }
+ ;
+
+ if is_false {
+ short_used_not_covered_closure_macro(0);
+ short_used_not_covered_closure_line_break_no_block_embedded_branch(0);
+ short_used_not_covered_closure_line_break_block_embedded_branch(0);
+ }
+ short_used_covered_closure_macro(0);
+ short_used_covered_closure_line_break_no_block_embedded_branch(0);
+ short_used_covered_closure_line_break_block_embedded_branch(0);
+}
diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map
new file mode 100644
index 000000000..90eeb1a66
--- /dev/null
+++ b/tests/coverage/closure_bug.cov-map
@@ -0,0 +1,133 @@
+Function name: closure_bug::main
+Raw bytes (201): 0x[01, 01, 26, 01, 05, 05, 02, 05, 02, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 82, 01, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 01, 06, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 97, 01, 02, 09, 00, 0a, 97, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 92, 01, 00, 17, 00, 18, 8f, 01, 02, 09, 00, 0a, 8f, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 8a, 01, 00, 17, 00, 18, 87, 01, 02, 09, 00, 0a, 87, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 82, 01, 00, 17, 00, 18, 7f, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 38
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 3 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 5 operands: lhs = Counter(2), rhs = Expression(36, Sub)
+- expression 6 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 7 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 8 operands: lhs = Counter(2), rhs = Expression(36, Sub)
+- expression 9 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 11 operands: lhs = Expression(35, Add), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(2), rhs = Expression(36, Sub)
+- expression 13 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 14 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 15 operands: lhs = Counter(3), rhs = Expression(34, Sub)
+- expression 16 operands: lhs = Expression(35, Add), rhs = Counter(3)
+- expression 17 operands: lhs = Counter(2), rhs = Expression(36, Sub)
+- expression 18 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 19 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 20 operands: lhs = Counter(3), rhs = Expression(34, Sub)
+- expression 21 operands: lhs = Expression(35, Add), rhs = Counter(3)
+- expression 22 operands: lhs = Counter(2), rhs = Expression(36, Sub)
+- expression 23 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 24 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 25 operands: lhs = Expression(33, Add), rhs = Counter(4)
+- expression 26 operands: lhs = Counter(3), rhs = Expression(34, Sub)
+- expression 27 operands: lhs = Expression(35, Add), rhs = Counter(3)
+- expression 28 operands: lhs = Counter(2), rhs = Expression(36, Sub)
+- expression 29 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 30 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 31 operands: lhs = Counter(4), rhs = Expression(32, Sub)
+- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(4)
+- expression 33 operands: lhs = Counter(3), rhs = Expression(34, Sub)
+- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(3)
+- expression 35 operands: lhs = Counter(2), rhs = Expression(36, Sub)
+- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(2)
+- expression 37 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 17
+- Code(Counter(0)) at (prev + 6, 1) to (start + 3, 10)
+- Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14)
+- Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 24)
+ = (c0 - c1)
+- Code(Expression(37, Add)) at (prev + 2, 9) to (start + 0, 10)
+ = (c1 + (c0 - c1))
+- Code(Expression(37, Add)) at (prev + 6, 5) to (start + 1, 14)
+ = (c1 + (c0 - c1))
+- Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(36, Sub)) at (prev + 0, 23) to (start + 0, 24)
+ = ((c1 + (c0 - c1)) - c2)
+- Code(Expression(35, Add)) at (prev + 2, 9) to (start + 0, 10)
+ = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(35, Add)) at (prev + 6, 5) to (start + 1, 14)
+ = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(34, Sub)) at (prev + 0, 23) to (start + 0, 24)
+ = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
+- Code(Expression(33, Add)) at (prev + 2, 9) to (start + 0, 10)
+ = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Expression(33, Add)) at (prev + 6, 5) to (start + 1, 14)
+ = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23)
+- Code(Expression(32, Sub)) at (prev + 0, 23) to (start + 0, 24)
+ = ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)
+- Code(Expression(31, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+
+Function name: closure_bug::main::{closure#0}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0d, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 13, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+ = (c1 + (c0 - c1))
+
+Function name: closure_bug::main::{closure#1}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 16, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 22, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+ = (c1 + (c0 - c1))
+
+Function name: closure_bug::main::{closure#2}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1f, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 31, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+ = (c1 + (c0 - c1))
+
+Function name: closure_bug::main::{closure#3}
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 28, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 40, 9) to (start + 0, 18)
+- Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
+- Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
+ = (c1 + (c0 - c1))
+
diff --git a/tests/coverage/closure_bug.coverage b/tests/coverage/closure_bug.coverage
new file mode 100644
index 000000000..f3299834b
--- /dev/null
+++ b/tests/coverage/closure_bug.coverage
@@ -0,0 +1,53 @@
+ LL| |// Regression test for #115930.
+ LL| |// All of these closures are identical, and should produce identical output in
+ LL| |// the coverage report. However, an unstable sort was causing them to be treated
+ LL| |// inconsistently when preparing coverage spans.
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let truthy = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let a
+ LL| | =
+ LL| | |
+ LL| | |
+ LL| 2| if truthy { true } else { false };
+ ^0
+ LL| |
+ LL| 1| a();
+ LL| 1| if truthy { a(); }
+ ^0
+ LL| |
+ LL| 1| let b
+ LL| | =
+ LL| | |
+ LL| | |
+ LL| 2| if truthy { true } else { false };
+ ^0
+ LL| |
+ LL| 1| b();
+ LL| 1| if truthy { b(); }
+ ^0
+ LL| |
+ LL| 1| let c
+ LL| | =
+ LL| | |
+ LL| | |
+ LL| 2| if truthy { true } else { false };
+ ^0
+ LL| |
+ LL| 1| c();
+ LL| 1| if truthy { c(); }
+ ^0
+ LL| |
+ LL| 1| let d
+ LL| | =
+ LL| | |
+ LL| | |
+ LL| 2| if truthy { true } else { false };
+ ^0
+ LL| |
+ LL| 1| d();
+ LL| 1| if truthy { d(); }
+ ^0
+ LL| 1|}
+
diff --git a/tests/coverage/closure_bug.rs b/tests/coverage/closure_bug.rs
new file mode 100644
index 000000000..739bc5f0b
--- /dev/null
+++ b/tests/coverage/closure_bug.rs
@@ -0,0 +1,44 @@
+// Regression test for #115930.
+// All of these closures are identical, and should produce identical output in
+// the coverage report. However, an unstable sort was causing them to be treated
+// inconsistently when preparing coverage spans.
+
+fn main() {
+ let truthy = std::env::args().len() == 1;
+
+ let a
+ =
+ |
+ |
+ if truthy { true } else { false };
+
+ a();
+ if truthy { a(); }
+
+ let b
+ =
+ |
+ |
+ if truthy { true } else { false };
+
+ b();
+ if truthy { b(); }
+
+ let c
+ =
+ |
+ |
+ if truthy { true } else { false };
+
+ c();
+ if truthy { c(); }
+
+ let d
+ =
+ |
+ |
+ if truthy { true } else { false };
+
+ d();
+ if truthy { d(); }
+}
diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map
new file mode 100644
index 000000000..b02c7e2e4
--- /dev/null
+++ b/tests/coverage/closure_macro.cov-map
@@ -0,0 +1,36 @@
+Function name: closure_macro::load_configuration_files
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2)
+
+Function name: closure_macro::main
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 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)
+Number of file 0 mappings: 7
+- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33)
+- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
+ = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
+ = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
+- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: closure_macro::main::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 12, 00, 54]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 35, 18) to (start + 0, 84)
+
diff --git a/tests/coverage/closure_macro.coverage b/tests/coverage/closure_macro.coverage
new file mode 100644
index 000000000..0f2c917e0
--- /dev/null
+++ b/tests/coverage/closure_macro.coverage
@@ -0,0 +1,42 @@
+ LL| |// compile-flags: --edition=2018
+ LL| |#![feature(coverage_attribute)]
+ LL| |
+ LL| |macro_rules! bail {
+ LL| | ($msg:literal $(,)?) => {
+ LL| | if $msg.len() > 0 {
+ LL| | println!("no msg");
+ LL| | } else {
+ LL| | println!($msg);
+ LL| | }
+ LL| | return Err(String::from($msg));
+ LL| | };
+ LL| |}
+ LL| |
+ LL| |macro_rules! on_error {
+ LL| | ($value:expr, $error_message:expr) => {
+ LL| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+ LL| | let message = format!($error_message, e);
+ LL| | if message.len() > 0 {
+ LL| | println!("{}", message);
+ LL| | Ok(String::from("ok"))
+ LL| | } else {
+ LL| | bail!("error");
+ LL| | }
+ LL| | })
+ LL| | };
+ LL| |}
+ LL| |
+ LL| 1|fn load_configuration_files() -> Result<String, String> {
+ LL| 1| Ok(String::from("config"))
+ LL| 1|}
+ LL| |
+ LL| 1|pub fn main() -> Result<(), String> {
+ LL| 1| println!("Starting service");
+ LL| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+ ^0
+ LL| |
+ LL| 1| let startup_delay_duration = String::from("arg");
+ LL| 1| let _ = (config, startup_delay_duration);
+ LL| 1| Ok(())
+ LL| 1|}
+
diff --git a/tests/coverage/closure_macro.rs b/tests/coverage/closure_macro.rs
new file mode 100644
index 000000000..9b289141c
--- /dev/null
+++ b/tests/coverage/closure_macro.rs
@@ -0,0 +1,40 @@
+// compile-flags: --edition=2018
+#![feature(coverage_attribute)]
+
+macro_rules! bail {
+ ($msg:literal $(,)?) => {
+ if $msg.len() > 0 {
+ println!("no msg");
+ } else {
+ println!($msg);
+ }
+ return Err(String::from($msg));
+ };
+}
+
+macro_rules! on_error {
+ ($value:expr, $error_message:expr) => {
+ $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+ let message = format!($error_message, e);
+ if message.len() > 0 {
+ println!("{}", message);
+ Ok(String::from("ok"))
+ } else {
+ bail!("error");
+ }
+ })
+ };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+ Ok(String::from("config"))
+}
+
+pub fn main() -> Result<(), String> {
+ println!("Starting service");
+ let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+ let startup_delay_duration = String::from("arg");
+ let _ = (config, startup_delay_duration);
+ Ok(())
+}
diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map
new file mode 100644
index 000000000..7f8666948
--- /dev/null
+++ b/tests/coverage/closure_macro_async.cov-map
@@ -0,0 +1,44 @@
+Function name: closure_macro_async::load_configuration_files
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2)
+
+Function name: closure_macro_async::test
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 00, 2b]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 43)
+
+Function name: closure_macro_async::test::{closure#0}
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 21, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 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)
+Number of file 0 mappings: 7
+- Code(Counter(0)) at (prev + 33, 43) to (start + 1, 33)
+- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
+ = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
+ = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
+- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: closure_macro_async::test::{closure#0}::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 12, 00, 54]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 35, 18) to (start + 0, 84)
+
diff --git a/tests/coverage/closure_macro_async.coverage b/tests/coverage/closure_macro_async.coverage
new file mode 100644
index 000000000..74247f1bc
--- /dev/null
+++ b/tests/coverage/closure_macro_async.coverage
@@ -0,0 +1,79 @@
+ LL| |// compile-flags: --edition=2018
+ LL| |#![feature(coverage_attribute)]
+ LL| |
+ LL| |macro_rules! bail {
+ LL| | ($msg:literal $(,)?) => {
+ LL| | if $msg.len() > 0 {
+ LL| | println!("no msg");
+ LL| | } else {
+ LL| | println!($msg);
+ LL| | }
+ LL| | return Err(String::from($msg));
+ LL| | };
+ LL| |}
+ LL| |
+ LL| |macro_rules! on_error {
+ LL| | ($value:expr, $error_message:expr) => {
+ LL| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+ LL| | let message = format!($error_message, e);
+ LL| | if message.len() > 0 {
+ LL| | println!("{}", message);
+ LL| | Ok(String::from("ok"))
+ LL| | } else {
+ LL| | bail!("error");
+ LL| | }
+ LL| | })
+ LL| | };
+ LL| |}
+ LL| |
+ LL| 1|fn load_configuration_files() -> Result<String, String> {
+ LL| 1| Ok(String::from("config"))
+ LL| 1|}
+ LL| |
+ LL| 1|pub async fn test() -> Result<(), String> {
+ LL| 1| println!("Starting service");
+ LL| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+ ^0
+ LL| |
+ LL| 1| let startup_delay_duration = String::from("arg");
+ LL| 1| let _ = (config, startup_delay_duration);
+ LL| 1| Ok(())
+ LL| 1|}
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |fn main() {
+ LL| | executor::block_on(test()).unwrap();
+ LL| |}
+ LL| |
+ LL| |mod executor {
+ LL| | use core::{
+ LL| | future::Future,
+ LL| | pin::Pin,
+ LL| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ LL| | };
+ LL| |
+ LL| | #[coverage(off)]
+ LL| | pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ LL| | let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ LL| | use std::hint::unreachable_unchecked;
+ LL| | static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ LL| | #[coverage(off)]
+ LL| | |_| unsafe { unreachable_unchecked() }, // clone
+ LL| | #[coverage(off)]
+ LL| | |_| unsafe { unreachable_unchecked() }, // wake
+ LL| | #[coverage(off)]
+ LL| | |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ LL| | #[coverage(off)]
+ LL| | |_| (),
+ LL| | );
+ LL| | let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ LL| | let mut context = Context::from_waker(&waker);
+ LL| |
+ LL| | loop {
+ LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ LL| | break val;
+ LL| | }
+ LL| | }
+ LL| | }
+ LL| |}
+
diff --git a/tests/coverage/closure_macro_async.rs b/tests/coverage/closure_macro_async.rs
new file mode 100644
index 000000000..b4275599e
--- /dev/null
+++ b/tests/coverage/closure_macro_async.rs
@@ -0,0 +1,77 @@
+// compile-flags: --edition=2018
+#![feature(coverage_attribute)]
+
+macro_rules! bail {
+ ($msg:literal $(,)?) => {
+ if $msg.len() > 0 {
+ println!("no msg");
+ } else {
+ println!($msg);
+ }
+ return Err(String::from($msg));
+ };
+}
+
+macro_rules! on_error {
+ ($value:expr, $error_message:expr) => {
+ $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+ let message = format!($error_message, e);
+ if message.len() > 0 {
+ println!("{}", message);
+ Ok(String::from("ok"))
+ } else {
+ bail!("error");
+ }
+ })
+ };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+ Ok(String::from("config"))
+}
+
+pub async fn test() -> Result<(), String> {
+ println!("Starting service");
+ let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+ let startup_delay_duration = String::from("arg");
+ let _ = (config, startup_delay_duration);
+ Ok(())
+}
+
+#[coverage(off)]
+fn main() {
+ executor::block_on(test()).unwrap();
+}
+
+mod executor {
+ use core::{
+ future::Future,
+ pin::Pin,
+ task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ };
+
+ #[coverage(off)]
+ pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ use std::hint::unreachable_unchecked;
+ static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ #[coverage(off)]
+ |_| unsafe { unreachable_unchecked() }, // clone
+ #[coverage(off)]
+ |_| unsafe { unreachable_unchecked() }, // wake
+ #[coverage(off)]
+ |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ #[coverage(off)]
+ |_| (),
+ );
+ let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ let mut context = Context::from_waker(&waker);
+
+ loop {
+ if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ break val;
+ }
+ }
+ }
+}
diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map
new file mode 100644
index 000000000..7600d2d96
--- /dev/null
+++ b/tests/coverage/conditions.cov-map
@@ -0,0 +1,259 @@
+Function name: conditions::main
+Raw bytes (784): 0x[01, 01, 8e, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, b7, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, b2, 04, 0d, b7, 04, 09, 05, 00, 45, 00, 83, 01, 49, 45, 00, 7e, 31, 83, 01, 49, 45, 00, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, 76, 51, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, a7, 01, 55, 4d, 51, a3, 01, 59, a7, 01, 55, 4d, 51, 49, 9f, 01, a3, 01, 59, a7, 01, 55, 4d, 51, 61, 00, e3, 01, 65, 61, 00, de, 01, 2d, e3, 01, 65, 61, 00, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, d6, 01, 6d, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, 8b, 02, 71, 69, 6d, 87, 02, 75, 8b, 02, 71, 69, 6d, ff, 01, 00, 65, 83, 02, 87, 02, 75, 8b, 02, 71, 69, 6d, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 79, 00, d7, 02, 7d, 79, 00, d2, 02, 29, d7, 02, 7d, 79, 00, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, ca, 02, 85, 01, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, f3, 03, 89, 01, 81, 01, 85, 01, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, da, 03, 19, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 9b, 04, 1d, 15, 19, 97, 04, 21, 9b, 04, 1d, 15, 19, 8f, 04, 9f, 04, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, a3, 04, ae, 04, a7, 04, ab, 04, 25, 29, 2d, 31, b2, 04, 0d, b7, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, b7, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, b2, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, ae, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 7e, 02, 0f, 00, 1c, 7a, 01, 0c, 00, 19, 76, 00, 1d, 00, 2a, 72, 00, 2e, 00, 3c, a3, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 9f, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9b, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e3, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, de, 01, 03, 11, 00, 1e, da, 01, 01, 10, 00, 1d, d6, 01, 00, 21, 00, 2e, d2, 01, 00, 32, 00, 40, 87, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 83, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, fb, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, e7, 03, 02, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d2, 02, 02, 0f, 00, 1c, ce, 02, 01, 0c, 00, 19, ca, 02, 00, 1d, 00, 2a, c6, 02, 00, 2e, 00, 3c, ef, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, eb, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 8f, 04, 05, 09, 00, 0a, e7, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, e2, 03, 02, 0f, 00, 1c, de, 03, 01, 0c, 00, 19, da, 03, 00, 1d, 00, 2a, d6, 03, 00, 2e, 00, 3c, 97, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 93, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 8b, 04, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 142
+- expression 0 operands: lhs = Counter(2), rhs = Expression(12, Add)
+- expression 1 operands: lhs = Expression(13, Add), rhs = Counter(16)
+- expression 2 operands: lhs = Expression(14, Add), rhs = Counter(15)
+- expression 3 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 4 operands: lhs = Counter(1), rhs = Zero
+- expression 5 operands: lhs = Expression(141, Add), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(1), rhs = Zero
+- expression 7 operands: lhs = Counter(3), rhs = Counter(13)
+- expression 8 operands: lhs = Expression(9, Sub), rhs = Counter(14)
+- expression 9 operands: lhs = Counter(3), rhs = Counter(13)
+- expression 10 operands: lhs = Expression(14, Add), rhs = Counter(15)
+- expression 11 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(16)
+- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(15)
+- expression 14 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 15 operands: lhs = Expression(140, Sub), rhs = Counter(3)
+- expression 16 operands: lhs = Expression(141, Add), rhs = Counter(2)
+- expression 17 operands: lhs = Counter(1), rhs = Zero
+- expression 18 operands: lhs = Counter(17), rhs = Zero
+- expression 19 operands: lhs = Expression(32, Add), rhs = Counter(18)
+- expression 20 operands: lhs = Counter(17), rhs = Zero
+- expression 21 operands: lhs = Expression(31, Sub), rhs = Counter(12)
+- expression 22 operands: lhs = Expression(32, Add), rhs = Counter(18)
+- expression 23 operands: lhs = Counter(17), rhs = Zero
+- expression 24 operands: lhs = Expression(30, Sub), rhs = Counter(19)
+- expression 25 operands: lhs = Expression(31, Sub), rhs = Counter(12)
+- expression 26 operands: lhs = Expression(32, Add), rhs = Counter(18)
+- expression 27 operands: lhs = Counter(17), rhs = Zero
+- expression 28 operands: lhs = Expression(29, Sub), rhs = Counter(20)
+- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(19)
+- expression 30 operands: lhs = Expression(31, Sub), rhs = Counter(12)
+- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(18)
+- expression 32 operands: lhs = Counter(17), rhs = Zero
+- expression 33 operands: lhs = Expression(41, Add), rhs = Counter(21)
+- expression 34 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 35 operands: lhs = Expression(40, Add), rhs = Counter(22)
+- expression 36 operands: lhs = Expression(41, Add), rhs = Counter(21)
+- expression 37 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 38 operands: lhs = Counter(18), rhs = Expression(39, Add)
+- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(22)
+- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(21)
+- expression 41 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 42 operands: lhs = Counter(24), rhs = Zero
+- expression 43 operands: lhs = Expression(56, Add), rhs = Counter(25)
+- expression 44 operands: lhs = Counter(24), rhs = Zero
+- expression 45 operands: lhs = Expression(55, Sub), rhs = Counter(11)
+- expression 46 operands: lhs = Expression(56, Add), rhs = Counter(25)
+- expression 47 operands: lhs = Counter(24), rhs = Zero
+- expression 48 operands: lhs = Expression(54, Sub), rhs = Counter(26)
+- expression 49 operands: lhs = Expression(55, Sub), rhs = Counter(11)
+- expression 50 operands: lhs = Expression(56, Add), rhs = Counter(25)
+- expression 51 operands: lhs = Counter(24), rhs = Zero
+- expression 52 operands: lhs = Expression(53, Sub), rhs = Counter(27)
+- expression 53 operands: lhs = Expression(54, Sub), rhs = Counter(26)
+- expression 54 operands: lhs = Expression(55, Sub), rhs = Counter(11)
+- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(25)
+- expression 56 operands: lhs = Counter(24), rhs = Zero
+- expression 57 operands: lhs = Expression(66, Add), rhs = Counter(28)
+- expression 58 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 59 operands: lhs = Expression(65, Add), rhs = Counter(29)
+- expression 60 operands: lhs = Expression(66, Add), rhs = Counter(28)
+- expression 61 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 62 operands: lhs = Expression(63, Add), rhs = Zero
+- expression 63 operands: lhs = Counter(25), rhs = Expression(64, Add)
+- expression 64 operands: lhs = Expression(65, Add), rhs = Counter(29)
+- expression 65 operands: lhs = Expression(66, Add), rhs = Counter(28)
+- expression 66 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 67 operands: lhs = Counter(31), rhs = Expression(122, Add)
+- expression 68 operands: lhs = Expression(123, Add), rhs = Counter(35)
+- expression 69 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 70 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 71 operands: lhs = Counter(30), rhs = Zero
+- expression 72 operands: lhs = Expression(85, Add), rhs = Counter(31)
+- expression 73 operands: lhs = Counter(30), rhs = Zero
+- expression 74 operands: lhs = Expression(84, Sub), rhs = Counter(10)
+- expression 75 operands: lhs = Expression(85, Add), rhs = Counter(31)
+- expression 76 operands: lhs = Counter(30), rhs = Zero
+- expression 77 operands: lhs = Expression(83, Sub), rhs = Counter(32)
+- expression 78 operands: lhs = Expression(84, Sub), rhs = Counter(10)
+- expression 79 operands: lhs = Expression(85, Add), rhs = Counter(31)
+- expression 80 operands: lhs = Counter(30), rhs = Zero
+- expression 81 operands: lhs = Expression(82, Sub), rhs = Counter(33)
+- expression 82 operands: lhs = Expression(83, Sub), rhs = Counter(32)
+- expression 83 operands: lhs = Expression(84, Sub), rhs = Counter(10)
+- expression 84 operands: lhs = Expression(85, Add), rhs = Counter(31)
+- expression 85 operands: lhs = Counter(30), rhs = Zero
+- expression 86 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 87 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 88 operands: lhs = Expression(123, Add), rhs = Counter(35)
+- expression 89 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 90 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 91 operands: lhs = Counter(4), rhs = Expression(132, Add)
+- expression 92 operands: lhs = Expression(133, Add), rhs = Counter(8)
+- expression 93 operands: lhs = Expression(134, Add), rhs = Counter(7)
+- expression 94 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 95 operands: lhs = Counter(31), rhs = Expression(122, Add)
+- expression 96 operands: lhs = Expression(123, Add), rhs = Counter(35)
+- expression 97 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 98 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 99 operands: lhs = Expression(121, Add), rhs = Counter(4)
+- expression 100 operands: lhs = Counter(31), rhs = Expression(122, Add)
+- expression 101 operands: lhs = Expression(123, Add), rhs = Counter(35)
+- expression 102 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 103 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 104 operands: lhs = Expression(120, Sub), rhs = Counter(9)
+- expression 105 operands: lhs = Expression(121, Add), rhs = Counter(4)
+- expression 106 operands: lhs = Counter(31), rhs = Expression(122, Add)
+- expression 107 operands: lhs = Expression(123, Add), rhs = Counter(35)
+- expression 108 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 109 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 110 operands: lhs = Expression(119, Sub), rhs = Counter(5)
+- expression 111 operands: lhs = Expression(120, Sub), rhs = Counter(9)
+- expression 112 operands: lhs = Expression(121, Add), rhs = Counter(4)
+- expression 113 operands: lhs = Counter(31), rhs = Expression(122, Add)
+- expression 114 operands: lhs = Expression(123, Add), rhs = Counter(35)
+- expression 115 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 116 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 117 operands: lhs = Expression(118, Sub), rhs = Counter(6)
+- expression 118 operands: lhs = Expression(119, Sub), rhs = Counter(5)
+- expression 119 operands: lhs = Expression(120, Sub), rhs = Counter(9)
+- expression 120 operands: lhs = Expression(121, Add), rhs = Counter(4)
+- expression 121 operands: lhs = Counter(31), rhs = Expression(122, Add)
+- expression 122 operands: lhs = Expression(123, Add), rhs = Counter(35)
+- expression 123 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 124 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 125 operands: lhs = Expression(134, Add), rhs = Counter(7)
+- expression 126 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 127 operands: lhs = Expression(133, Add), rhs = Counter(8)
+- expression 128 operands: lhs = Expression(134, Add), rhs = Counter(7)
+- expression 129 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 130 operands: lhs = Expression(131, Add), rhs = Expression(135, Add)
+- expression 131 operands: lhs = Counter(4), rhs = Expression(132, Add)
+- expression 132 operands: lhs = Expression(133, Add), rhs = Counter(8)
+- expression 133 operands: lhs = Expression(134, Add), rhs = Counter(7)
+- expression 134 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 135 operands: lhs = Expression(136, Add), rhs = Expression(139, Sub)
+- expression 136 operands: lhs = Expression(137, Add), rhs = Expression(138, Add)
+- expression 137 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 138 operands: lhs = Counter(11), rhs = Counter(12)
+- expression 139 operands: lhs = Expression(140, Sub), rhs = Counter(3)
+- expression 140 operands: lhs = Expression(141, Add), rhs = Counter(2)
+- expression 141 operands: lhs = Counter(1), rhs = Zero
+Number of file 0 mappings: 68
+- Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12)
+- Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10)
+ = (c2 + (((c13 + c14) + c15) + c16))
+- Code(Expression(141, Add)) at (prev + 0, 16) to (start + 0, 29)
+ = (c1 + Zero)
+- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 10)
+- Code(Expression(140, Sub)) at (prev + 2, 15) to (start + 0, 28)
+ = ((c1 + Zero) - c2)
+- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(9, Sub)) at (prev + 0, 29) to (start + 0, 42)
+ = (c3 - c13)
+- Code(Expression(8, Sub)) at (prev + 0, 46) to (start + 0, 60)
+ = ((c3 - c13) - c14)
+- Code(Expression(13, Add)) at (prev + 0, 61) to (start + 2, 10)
+ = ((c13 + c14) + c15)
+- Code(Counter(16)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(12, Add)) at (prev + 1, 9) to (start + 1, 18)
+ = (((c13 + c14) + c15) + c16)
+- Code(Expression(139, Sub)) at (prev + 3, 9) to (start + 0, 15)
+ = (((c1 + Zero) - c2) - c3)
+- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12)
+ = (c2 + (((c13 + c14) + c15) + c16))
+- Code(Counter(17)) at (prev + 1, 13) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(32, Add)) at (prev + 2, 8) to (start + 0, 21)
+ = (c17 + Zero)
+- Code(Counter(18)) at (prev + 0, 22) to (start + 2, 6)
+- Code(Expression(31, Sub)) at (prev + 2, 15) to (start + 0, 28)
+ = ((c17 + Zero) - c18)
+- Code(Expression(30, Sub)) at (prev + 1, 12) to (start + 0, 25)
+ = (((c17 + Zero) - c18) - c12)
+- Code(Expression(29, Sub)) at (prev + 0, 29) to (start + 0, 42)
+ = ((((c17 + Zero) - c18) - c12) - c19)
+- Code(Expression(28, Sub)) at (prev + 0, 46) to (start + 0, 60)
+ = (((((c17 + Zero) - c18) - c12) - c19) - c20)
+- Code(Expression(40, Add)) at (prev + 0, 61) to (start + 2, 10)
+ = ((c19 + c20) + c21)
+- Code(Counter(22)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(39, Add)) at (prev + 1, 9) to (start + 0, 23)
+ = (((c19 + c20) + c21) + c22)
+- Code(Counter(12)) at (prev + 2, 9) to (start + 0, 15)
+- Code(Expression(38, Add)) at (prev + 3, 8) to (start + 0, 12)
+ = (c18 + (((c19 + c20) + c21) + c22))
+- Code(Counter(23)) at (prev + 1, 13) to (start + 1, 16)
+- Code(Counter(24)) at (prev + 1, 17) to (start + 2, 10)
+- Code(Zero) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(56, Add)) at (prev + 2, 12) to (start + 0, 25)
+ = (c24 + Zero)
+- Code(Counter(25)) at (prev + 0, 26) to (start + 2, 10)
+- Code(Expression(55, Sub)) at (prev + 3, 17) to (start + 0, 30)
+ = ((c24 + Zero) - c25)
+- Code(Expression(54, Sub)) at (prev + 1, 16) to (start + 0, 29)
+ = (((c24 + Zero) - c25) - c11)
+- Code(Expression(53, Sub)) at (prev + 0, 33) to (start + 0, 46)
+ = ((((c24 + Zero) - c25) - c11) - c26)
+- Code(Expression(52, Sub)) at (prev + 0, 50) to (start + 0, 64)
+ = (((((c24 + Zero) - c25) - c11) - c26) - c27)
+- Code(Expression(65, Add)) at (prev + 0, 65) to (start + 2, 14)
+ = ((c26 + c27) + c28)
+- Code(Counter(29)) at (prev + 2, 14) to (start + 0, 15)
+- Code(Expression(64, Add)) at (prev + 1, 13) to (start + 0, 27)
+ = (((c26 + c27) + c28) + c29)
+- Code(Counter(11)) at (prev + 2, 13) to (start + 0, 19)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(62, Add)) at (prev + 2, 9) to (start + 1, 12)
+ = ((c25 + (((c26 + c27) + c28) + c29)) + Zero)
+- Code(Counter(30)) at (prev + 1, 13) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(121, Add)) at (prev + 2, 9) to (start + 0, 10)
+ = (c31 + (((c32 + c33) + c34) + c35))
+- Code(Expression(85, Add)) at (prev + 0, 16) to (start + 0, 29)
+ = (c30 + Zero)
+- Code(Counter(31)) at (prev + 0, 30) to (start + 2, 6)
+- Code(Expression(84, Sub)) at (prev + 2, 15) to (start + 0, 28)
+ = ((c30 + Zero) - c31)
+- Code(Expression(83, Sub)) at (prev + 1, 12) to (start + 0, 25)
+ = (((c30 + Zero) - c31) - c10)
+- Code(Expression(82, Sub)) at (prev + 0, 29) to (start + 0, 42)
+ = ((((c30 + Zero) - c31) - c10) - c32)
+- Code(Expression(81, Sub)) at (prev + 0, 46) to (start + 0, 60)
+ = (((((c30 + Zero) - c31) - c10) - c32) - c33)
+- Code(Expression(123, Add)) at (prev + 0, 61) to (start + 2, 10)
+ = ((c32 + c33) + c34)
+- Code(Counter(35)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(122, Add)) at (prev + 1, 9) to (start + 0, 23)
+ = (((c32 + c33) + c34) + c35)
+- Code(Counter(10)) at (prev + 2, 13) to (start + 2, 15)
+- Code(Expression(131, Add)) at (prev + 5, 9) to (start + 0, 10)
+ = (c4 + (((c5 + c6) + c7) + c8))
+- Code(Expression(121, Add)) at (prev + 0, 16) to (start + 0, 29)
+ = (c31 + (((c32 + c33) + c34) + c35))
+- Code(Counter(4)) at (prev + 0, 30) to (start + 2, 6)
+- Code(Expression(120, Sub)) at (prev + 2, 15) to (start + 0, 28)
+ = ((c31 + (((c32 + c33) + c34) + c35)) - c4)
+- Code(Expression(119, Sub)) at (prev + 1, 12) to (start + 0, 25)
+ = (((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9)
+- Code(Expression(118, Sub)) at (prev + 0, 29) to (start + 0, 42)
+ = ((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5)
+- Code(Expression(117, Sub)) at (prev + 0, 46) to (start + 0, 60)
+ = (((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5) - c6)
+- Code(Expression(133, Add)) at (prev + 0, 61) to (start + 2, 10)
+ = ((c5 + c6) + c7)
+- Code(Counter(8)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(132, Add)) at (prev + 1, 9) to (start + 0, 23)
+ = (((c5 + c6) + c7) + c8)
+- Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15)
+- Code(Expression(130, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = ((c4 + (((c5 + c6) + c7) + c8)) + (((c9 + c10) + (c11 + c12)) + (((c1 + Zero) - c2) - c3)))
+
diff --git a/tests/coverage/conditions.coverage b/tests/coverage/conditions.coverage
new file mode 100644
index 000000000..473335ff6
--- /dev/null
+++ b/tests/coverage/conditions.coverage
@@ -0,0 +1,93 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let mut countdown = 0;
+ LL| 1| if true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| |
+ LL| | const B: u32 = 100;
+ LL| 1| let x = if countdown > 7 {
+ LL| 1| countdown -= 4;
+ LL| 1| B
+ LL| 0| } else if countdown > 2 {
+ LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 {
+ LL| 0| countdown = 0;
+ LL| 0| }
+ LL| 0| countdown -= 5;
+ LL| 0| countdown
+ LL| | } else {
+ LL| 0| return;
+ LL| | };
+ LL| |
+ LL| 1| let mut countdown = 0;
+ LL| 1| if true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| |
+ LL| 1| if countdown > 7 {
+ LL| 1| countdown -= 4;
+ LL| 1| } else if countdown > 2 {
+ ^0
+ LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 {
+ LL| 0| countdown = 0;
+ LL| 0| }
+ LL| 0| countdown -= 5;
+ LL| | } else {
+ LL| 0| return;
+ LL| | }
+ LL| |
+ LL| 1| if true {
+ LL| 1| let mut countdown = 0;
+ LL| 1| if true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| |
+ LL| 1| if countdown > 7 {
+ LL| 1| countdown -= 4;
+ LL| 1| }
+ LL| 0| else if countdown > 2 {
+ LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 {
+ LL| 0| countdown = 0;
+ LL| 0| }
+ LL| 0| countdown -= 5;
+ LL| | } else {
+ LL| 0| return;
+ LL| | }
+ LL| 0| }
+ LL| |
+ LL| 1| let mut countdown = 0;
+ LL| 1| if true {
+ LL| 1| countdown = 1;
+ LL| 1| }
+ ^0
+ LL| |
+ LL| 1| let z = if countdown > 7 {
+ ^0
+ LL| 0| countdown -= 4;
+ LL| 1| } else if countdown > 2 {
+ LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 {
+ LL| 0| countdown = 0;
+ LL| 0| }
+ LL| 0| countdown -= 5;
+ LL| | } else {
+ LL| 1| let should_be_reachable = countdown;
+ LL| 1| println!("reached");
+ LL| 1| return;
+ LL| | };
+ LL| |
+ LL| 0| let w = if countdown > 7 {
+ LL| 0| countdown -= 4;
+ LL| 0| } else if countdown > 2 {
+ LL| 0| if countdown < 1 || countdown > 5 || countdown != 9 {
+ LL| 0| countdown = 0;
+ LL| 0| }
+ LL| 0| countdown -= 5;
+ LL| | } else {
+ LL| 0| return;
+ LL| | };
+ LL| 1|}
+
diff --git a/tests/coverage/conditions.rs b/tests/coverage/conditions.rs
new file mode 100644
index 000000000..fa7f2a116
--- /dev/null
+++ b/tests/coverage/conditions.rs
@@ -0,0 +1,86 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+ let mut countdown = 0;
+ if true {
+ countdown = 10;
+ }
+
+ const B: u32 = 100;
+ let x = if countdown > 7 {
+ countdown -= 4;
+ B
+ } else if countdown > 2 {
+ if countdown < 1 || countdown > 5 || countdown != 9 {
+ countdown = 0;
+ }
+ countdown -= 5;
+ countdown
+ } else {
+ return;
+ };
+
+ let mut countdown = 0;
+ if true {
+ countdown = 10;
+ }
+
+ if countdown > 7 {
+ countdown -= 4;
+ } else if countdown > 2 {
+ if countdown < 1 || countdown > 5 || countdown != 9 {
+ countdown = 0;
+ }
+ countdown -= 5;
+ } else {
+ return;
+ }
+
+ if true {
+ let mut countdown = 0;
+ if true {
+ countdown = 10;
+ }
+
+ if countdown > 7 {
+ countdown -= 4;
+ }
+ else if countdown > 2 {
+ if countdown < 1 || countdown > 5 || countdown != 9 {
+ countdown = 0;
+ }
+ countdown -= 5;
+ } else {
+ return;
+ }
+ }
+
+ let mut countdown = 0;
+ if true {
+ countdown = 1;
+ }
+
+ let z = if countdown > 7 {
+ countdown -= 4;
+ } else if countdown > 2 {
+ if countdown < 1 || countdown > 5 || countdown != 9 {
+ countdown = 0;
+ }
+ countdown -= 5;
+ } else {
+ let should_be_reachable = countdown;
+ println!("reached");
+ return;
+ };
+
+ let w = if countdown > 7 {
+ countdown -= 4;
+ } else if countdown > 2 {
+ if countdown < 1 || countdown > 5 || countdown != 9 {
+ countdown = 0;
+ }
+ countdown -= 5;
+ } else {
+ return;
+ };
+}
diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map
new file mode 100644
index 000000000..82f3d7c60
--- /dev/null
+++ b/tests/coverage/continue.cov-map
@@ -0,0 +1,79 @@
+Function name: continue::main
+Raw bytes (210): 0x[01, 01, 1c, 01, 07, 05, 09, 03, 0d, 0d, 1f, 11, 15, 1b, 19, 0d, 1f, 11, 15, 19, 33, 1d, 21, 2f, 25, 19, 33, 1d, 21, 25, 47, 29, 2d, 43, 31, 25, 47, 29, 2d, 31, 5f, 35, 39, 57, 3d, 31, 5f, 35, 39, 35, 39, 3d, 41, 6b, 45, 3d, 41, 49, 45, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 15, 03, 09, 00, 0e, 2f, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 1d, 03, 09, 00, 0e, 43, 02, 0e, 00, 13, 3e, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 57, 03, 0e, 00, 13, 52, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 5f, 04, 09, 00, 0e, 6b, 02, 0e, 00, 13, 66, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 49, 04, 11, 00, 16, 41, 03, 09, 00, 0e, 6f, 02, 0d, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 28
+- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(3), rhs = Expression(7, Add)
+- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(6)
+- expression 6 operands: lhs = Counter(3), rhs = Expression(7, Add)
+- expression 7 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 8 operands: lhs = Counter(6), rhs = Expression(12, Add)
+- expression 9 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(9)
+- expression 11 operands: lhs = Counter(6), rhs = Expression(12, Add)
+- expression 12 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 13 operands: lhs = Counter(9), rhs = Expression(17, Add)
+- expression 14 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 15 operands: lhs = Expression(16, Add), rhs = Counter(12)
+- expression 16 operands: lhs = Counter(9), rhs = Expression(17, Add)
+- expression 17 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 18 operands: lhs = Counter(12), rhs = Expression(23, Add)
+- expression 19 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(15)
+- expression 21 operands: lhs = Counter(12), rhs = Expression(23, Add)
+- expression 22 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 23 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 24 operands: lhs = Counter(15), rhs = Counter(16)
+- expression 25 operands: lhs = Expression(26, Add), rhs = Counter(17)
+- expression 26 operands: lhs = Counter(15), rhs = Counter(16)
+- expression 27 operands: lhs = Counter(18), rhs = Counter(17)
+Number of file 0 mappings: 30
+- Code(Counter(0)) at (prev + 3, 1) to (start + 3, 18)
+- Code(Expression(0, Add)) at (prev + 4, 14) to (start + 0, 19)
+ = (c0 + (c1 + c2))
+- Code(Expression(2, Sub)) at (prev + 1, 15) to (start + 0, 22)
+ = ((c0 + (c1 + c2)) - c3)
+- Code(Counter(1)) at (prev + 2, 17) to (start + 0, 25)
+- Code(Counter(2)) at (prev + 2, 18) to (start + 4, 14)
+- Code(Expression(6, Add)) at (prev + 6, 14) to (start + 0, 19)
+ = (c3 + (c4 + c5))
+- Code(Expression(5, Sub)) at (prev + 1, 15) to (start + 0, 22)
+ = ((c3 + (c4 + c5)) - c6)
+- Code(Counter(5)) at (prev + 1, 22) to (start + 2, 14)
+- Code(Counter(4)) at (prev + 4, 17) to (start + 0, 25)
+- Code(Counter(5)) at (prev + 3, 9) to (start + 0, 14)
+- Code(Expression(11, Add)) at (prev + 2, 14) to (start + 0, 19)
+ = (c6 + (c7 + c8))
+- Code(Expression(10, Sub)) at (prev + 1, 15) to (start + 0, 22)
+ = ((c6 + (c7 + c8)) - c9)
+- Code(Counter(7)) at (prev + 1, 21) to (start + 2, 14)
+- Code(Counter(8)) at (prev + 4, 17) to (start + 0, 25)
+- Code(Counter(7)) at (prev + 3, 9) to (start + 0, 14)
+- Code(Expression(16, Add)) at (prev + 2, 14) to (start + 0, 19)
+ = (c9 + (c10 + c11))
+- Code(Expression(15, Sub)) at (prev + 1, 12) to (start + 0, 19)
+ = ((c9 + (c10 + c11)) - c12)
+- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 21)
+- Code(Counter(11)) at (prev + 1, 10) to (start + 1, 14)
+- Code(Expression(21, Add)) at (prev + 3, 14) to (start + 0, 19)
+ = (c12 + (c13 + c14))
+- Code(Expression(20, Sub)) at (prev + 1, 15) to (start + 0, 22)
+ = ((c12 + (c13 + c14)) - c15)
+- Code(Counter(14)) at (prev + 1, 22) to (start + 2, 14)
+- Code(Counter(13)) at (prev + 3, 18) to (start + 2, 14)
+- Code(Expression(23, Add)) at (prev + 4, 9) to (start + 0, 14)
+ = (c13 + c14)
+- Code(Expression(26, Add)) at (prev + 2, 14) to (start + 0, 19)
+ = (c15 + c16)
+- Code(Expression(25, Sub)) at (prev + 1, 15) to (start + 0, 22)
+ = ((c15 + c16) - c17)
+- Code(Counter(16)) at (prev + 1, 22) to (start + 2, 14)
+- Code(Counter(18)) at (prev + 4, 17) to (start + 0, 22)
+- Code(Counter(16)) at (prev + 3, 9) to (start + 0, 14)
+- Code(Expression(27, Add)) at (prev + 2, 13) to (start + 1, 2)
+ = (c18 + c17)
+
diff --git a/tests/coverage/continue.coverage b/tests/coverage/continue.coverage
new file mode 100644
index 000000000..4916cac00
--- /dev/null
+++ b/tests/coverage/continue.coverage
@@ -0,0 +1,70 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let mut x = 0;
+ LL| 11| for _ in 0..10 {
+ LL| 10| match is_true {
+ LL| | true => {
+ LL| 10| continue;
+ LL| | }
+ LL| 0| _ => {
+ LL| 0| x = 1;
+ LL| 0| }
+ LL| 0| }
+ LL| 0| x = 3;
+ LL| | }
+ LL| 11| for _ in 0..10 {
+ LL| 10| match is_true {
+ LL| 0| false => {
+ LL| 0| x = 1;
+ LL| 0| }
+ LL| | _ => {
+ LL| 10| continue;
+ LL| | }
+ LL| | }
+ LL| 0| x = 3;
+ LL| | }
+ LL| 11| for _ in 0..10 {
+ LL| 10| match is_true {
+ LL| 10| true => {
+ LL| 10| x = 1;
+ LL| 10| }
+ LL| | _ => {
+ LL| 0| continue;
+ LL| | }
+ LL| | }
+ LL| 10| x = 3;
+ LL| | }
+ LL| 11| for _ in 0..10 {
+ LL| 10| if is_true {
+ LL| 10| continue;
+ LL| 0| }
+ LL| 0| x = 3;
+ LL| | }
+ LL| 11| for _ in 0..10 {
+ LL| 10| match is_true {
+ LL| 0| false => {
+ LL| 0| x = 1;
+ LL| 0| }
+ LL| 10| _ => {
+ LL| 10| let _ = x;
+ LL| 10| }
+ LL| | }
+ LL| 10| x = 3;
+ LL| | }
+ LL| 1| for _ in 0..10 {
+ LL| 1| match is_true {
+ LL| 0| false => {
+ LL| 0| x = 1;
+ LL| 0| }
+ LL| | _ => {
+ LL| 1| break;
+ LL| | }
+ LL| | }
+ LL| 0| x = 3;
+ LL| | }
+ LL| 1| let _ = x;
+ LL| 1|}
+
diff --git a/tests/coverage/continue.rs b/tests/coverage/continue.rs
new file mode 100644
index 000000000..624aa9834
--- /dev/null
+++ b/tests/coverage/continue.rs
@@ -0,0 +1,69 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+ let is_true = std::env::args().len() == 1;
+
+ let mut x = 0;
+ for _ in 0..10 {
+ match is_true {
+ true => {
+ continue;
+ }
+ _ => {
+ x = 1;
+ }
+ }
+ x = 3;
+ }
+ for _ in 0..10 {
+ match is_true {
+ false => {
+ x = 1;
+ }
+ _ => {
+ continue;
+ }
+ }
+ x = 3;
+ }
+ for _ in 0..10 {
+ match is_true {
+ true => {
+ x = 1;
+ }
+ _ => {
+ continue;
+ }
+ }
+ x = 3;
+ }
+ for _ in 0..10 {
+ if is_true {
+ continue;
+ }
+ x = 3;
+ }
+ for _ in 0..10 {
+ match is_true {
+ false => {
+ x = 1;
+ }
+ _ => {
+ let _ = x;
+ }
+ }
+ x = 3;
+ }
+ for _ in 0..10 {
+ match is_true {
+ false => {
+ x = 1;
+ }
+ _ => {
+ break;
+ }
+ }
+ x = 3;
+ }
+ let _ = x;
+}
diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map
new file mode 100644
index 000000000..2f4936d9a
--- /dev/null
+++ b/tests/coverage/coroutine.cov-map
@@ -0,0 +1,53 @@
+Function name: coroutine::get_u32
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 01, 01, 0b, 05, 01, 0e, 00, 13, 02, 00, 1d, 00, 3c, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 11, 1) to (start + 1, 11)
+- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 29) to (start + 0, 60)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: coroutine::main
+Raw bytes (65): 0x[01, 01, 08, 05, 07, 09, 0d, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 0f, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 8
+- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 3 operands: lhs = Expression(7, Sub), rhs = Counter(6)
+- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 5 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(6)
+- expression 7 operands: lhs = Counter(4), rhs = Counter(5)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 22)
+- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46)
+- Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45)
+- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 53)
+ = (c1 + (c2 + c3))
+- Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46)
+- Code(Expression(7, Sub)) at (prev + 1, 34) to (start + 0, 39)
+ = (c4 - c5)
+- Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 46)
+ = ((c4 - c5) - c6)
+- Code(Expression(5, Add)) at (prev + 1, 14) to (start + 0, 53)
+ = (c5 + c6)
+- Code(Expression(6, Sub)) at (prev + 2, 1) to (start + 0, 2)
+ = ((c4 - c5) - c6)
+
+Function name: coroutine::main::{closure#0}
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 1c, 01, 1f, 05, 02, 10, 01, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 17, 28) to (start + 1, 31)
+- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6)
+
diff --git a/tests/coverage/coroutine.coverage b/tests/coverage/coroutine.coverage
new file mode 100644
index 000000000..3a9791a0d
--- /dev/null
+++ b/tests/coverage/coroutine.coverage
@@ -0,0 +1,32 @@
+ LL| |#![feature(coroutines, coroutine_trait)]
+ LL| |
+ LL| |use std::ops::{Coroutine, CoroutineState};
+ LL| |use std::pin::Pin;
+ LL| |
+ LL| |// The following implementation of a function called from a `yield` statement
+ LL| |// (apparently requiring the Result and the `String` type or constructor)
+ LL| |// creates conditions where the `coroutine::StateTransform` MIR transform will
+ LL| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+ LL| |// to handle this condition, and still report dead block coverage.
+ LL| 1|fn get_u32(val: bool) -> Result<u32, String> {
+ LL| 1| if val { Ok(1) } else { Err(String::from("some error")) }
+ ^0
+ LL| 1|}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1| let mut coroutine = || {
+ LL| 1| yield get_u32(is_true);
+ LL| 1| return "foo";
+ LL| 1| };
+ LL| |
+ LL| 1| match Pin::new(&mut coroutine).resume(()) {
+ LL| 1| CoroutineState::Yielded(Ok(1)) => {}
+ LL| 0| _ => panic!("unexpected return from resume"),
+ LL| | }
+ LL| 1| match Pin::new(&mut coroutine).resume(()) {
+ LL| 1| CoroutineState::Complete("foo") => {}
+ LL| 0| _ => panic!("unexpected return from resume"),
+ LL| | }
+ LL| 1|}
+
diff --git a/tests/coverage/coroutine.rs b/tests/coverage/coroutine.rs
new file mode 100644
index 000000000..86d19af6f
--- /dev/null
+++ b/tests/coverage/coroutine.rs
@@ -0,0 +1,30 @@
+#![feature(coroutines, coroutine_trait)]
+
+use std::ops::{Coroutine, CoroutineState};
+use std::pin::Pin;
+
+// The following implementation of a function called from a `yield` statement
+// (apparently requiring the Result and the `String` type or constructor)
+// creates conditions where the `coroutine::StateTransform` MIR transform will
+// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+// to handle this condition, and still report dead block coverage.
+fn get_u32(val: bool) -> Result<u32, String> {
+ if val { Ok(1) } else { Err(String::from("some error")) }
+}
+
+fn main() {
+ let is_true = std::env::args().len() == 1;
+ let mut coroutine = || {
+ yield get_u32(is_true);
+ return "foo";
+ };
+
+ match Pin::new(&mut coroutine).resume(()) {
+ CoroutineState::Yielded(Ok(1)) => {}
+ _ => panic!("unexpected return from resume"),
+ }
+ match Pin::new(&mut coroutine).resume(()) {
+ CoroutineState::Complete("foo") => {}
+ _ => panic!("unexpected return from resume"),
+ }
+}
diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map
new file mode 100644
index 000000000..0b8a40a8c
--- /dev/null
+++ b/tests/coverage/dead_code.cov-map
@@ -0,0 +1,37 @@
+Function name: dead_code::main
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 27, 1) to (start + 7, 15)
+- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: dead_code::unused_fn (unused)
+Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Zero) at (prev + 15, 1) to (start + 7, 15)
+- Code(Zero) at (prev + 7, 16) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
+
+Function name: dead_code::unused_pub_fn_not_in_library (unused)
+Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Zero) at (prev + 3, 1) to (start + 7, 15)
+- Code(Zero) at (prev + 7, 16) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
+
diff --git a/tests/coverage/dead_code.coverage b/tests/coverage/dead_code.coverage
new file mode 100644
index 000000000..c4ee9f23f
--- /dev/null
+++ b/tests/coverage/dead_code.coverage
@@ -0,0 +1,39 @@
+ LL| |#![allow(dead_code, unused_assignments, unused_variables)]
+ LL| |
+ LL| 0|pub fn unused_pub_fn_not_in_library() {
+ LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 0| // dependent conditions.
+ LL| 0| let is_true = std::env::args().len() == 1;
+ LL| 0|
+ LL| 0| let mut countdown = 0;
+ LL| 0| if is_true {
+ LL| 0| countdown = 10;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| 0|fn unused_fn() {
+ LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 0| // dependent conditions.
+ LL| 0| let is_true = std::env::args().len() == 1;
+ LL| 0|
+ LL| 0| let mut countdown = 0;
+ LL| 0| if is_true {
+ LL| 0| countdown = 10;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let mut countdown = 0;
+ LL| 1| if is_true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| 1|}
+
diff --git a/tests/coverage/dead_code.rs b/tests/coverage/dead_code.rs
new file mode 100644
index 000000000..3492712a6
--- /dev/null
+++ b/tests/coverage/dead_code.rs
@@ -0,0 +1,37 @@
+#![allow(dead_code, unused_assignments, unused_variables)]
+
+pub fn unused_pub_fn_not_in_library() {
+ // 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 countdown = 0;
+ if is_true {
+ countdown = 10;
+ }
+}
+
+fn unused_fn() {
+ // 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 countdown = 0;
+ if is_true {
+ countdown = 10;
+ }
+}
+
+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 countdown = 0;
+ if is_true {
+ countdown = 10;
+ }
+}
diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/drop_trait.cov-map
new file mode 100644
index 000000000..203d1048b
--- /dev/null
+++ b/tests/coverage/drop_trait.cov-map
@@ -0,0 +1,21 @@
+Function name: <drop_trait::Firework as core::ops::drop::Drop>::drop
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 05, 02, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6)
+
+Function name: drop_trait::main
+Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0e, 01, 05, 0c, 05, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 14, 1) to (start + 5, 12)
+- Code(Counter(1)) at (prev + 6, 9) to (start + 1, 22)
+- Code(Zero) at (prev + 2, 6) to (start + 4, 11)
+- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2)
+ = (c1 + Zero)
+
diff --git a/tests/coverage/drop_trait.coverage b/tests/coverage/drop_trait.coverage
new file mode 100644
index 000000000..2c9439a93
--- /dev/null
+++ b/tests/coverage/drop_trait.coverage
@@ -0,0 +1,34 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |// failure-status: 1
+ LL| |
+ LL| |struct Firework {
+ LL| | strength: i32,
+ LL| |}
+ LL| |
+ LL| |impl Drop for Firework {
+ LL| 2| fn drop(&mut self) {
+ LL| 2| println!("BOOM times {}!!!", self.strength);
+ LL| 2| }
+ LL| |}
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| let _firecracker = Firework { strength: 1 };
+ LL| 1|
+ LL| 1| let _tnt = Firework { strength: 100 };
+ LL| 1|
+ LL| 1| if true {
+ LL| 1| println!("Exiting with error...");
+ LL| 1| return Err(1);
+ LL| 0| }
+ LL| 0|
+ LL| 0| let _ = Firework { strength: 1000 };
+ LL| 0|
+ LL| 0| Ok(())
+ LL| 1|}
+ LL| |
+ LL| |// Expected program output:
+ LL| |// Exiting with error...
+ LL| |// BOOM times 100!!!
+ LL| |// BOOM times 1!!!
+ LL| |// Error: 1
+
diff --git a/tests/coverage/drop_trait.rs b/tests/coverage/drop_trait.rs
new file mode 100644
index 000000000..7b062719c
--- /dev/null
+++ b/tests/coverage/drop_trait.rs
@@ -0,0 +1,33 @@
+#![allow(unused_assignments)]
+// failure-status: 1
+
+struct Firework {
+ strength: i32,
+}
+
+impl Drop for Firework {
+ fn drop(&mut self) {
+ println!("BOOM times {}!!!", self.strength);
+ }
+}
+
+fn main() -> Result<(), u8> {
+ let _firecracker = Firework { strength: 1 };
+
+ let _tnt = Firework { strength: 100 };
+
+ if true {
+ println!("Exiting with error...");
+ return Err(1);
+ }
+
+ let _ = Firework { strength: 1000 };
+
+ Ok(())
+}
+
+// Expected program output:
+// Exiting with error...
+// BOOM times 100!!!
+// BOOM times 1!!!
+// Error: 1
diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map
new file mode 100644
index 000000000..6e26c61aa
--- /dev/null
+++ b/tests/coverage/fn_sig_into_try.cov-map
@@ -0,0 +1,53 @@
+Function name: fn_sig_into_try::a
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 04, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+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, 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 = 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 - Zero)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (Zero + (c0 - Zero))
+
+Function name: fn_sig_into_try::c
+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 = 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 - Zero)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (Zero + (c0 - Zero))
+
+Function name: fn_sig_into_try::d
+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 = 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 - Zero)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (Zero + (c0 - Zero))
+
diff --git a/tests/coverage/fn_sig_into_try.coverage b/tests/coverage/fn_sig_into_try.coverage
new file mode 100644
index 000000000..f1ddb1da7
--- /dev/null
+++ b/tests/coverage/fn_sig_into_try.coverage
@@ -0,0 +1,45 @@
+ LL| |#![feature(coverage_attribute)]
+ LL| |// compile-flags: --edition=2021
+ LL| |
+ LL| |// Regression test for inconsistent handling of function signature spans that
+ LL| |// are followed by code using the `?` operator.
+ LL| |//
+ LL| |// For each of these similar functions, the line containing the function
+ LL| |// signature should be handled in the same way.
+ LL| |
+ LL| 1|fn a() -> Option<i32>
+ LL| 1|{
+ LL| 1| Some(7i32);
+ LL| 1| Some(0)
+ LL| 1|}
+ LL| |
+ LL| 1|fn b() -> Option<i32>
+ LL| 1|{
+ LL| 1| Some(7i32)?;
+ ^0
+ LL| 1| Some(0)
+ LL| 1|}
+ LL| |
+ LL| 1|fn c() -> Option<i32>
+ LL| 1|{
+ LL| 1| let _ = Some(7i32)?;
+ ^0
+ LL| 1| Some(0)
+ LL| 1|}
+ LL| |
+ LL| 1|fn d() -> Option<i32>
+ LL| 1|{
+ LL| 1| let _: () = ();
+ LL| 1| Some(7i32)?;
+ ^0
+ LL| 1| Some(0)
+ LL| 1|}
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |fn main() {
+ LL| | a();
+ LL| | b();
+ LL| | c();
+ LL| | d();
+ LL| |}
+
diff --git a/tests/coverage/fn_sig_into_try.rs b/tests/coverage/fn_sig_into_try.rs
new file mode 100644
index 000000000..92850c8a1
--- /dev/null
+++ b/tests/coverage/fn_sig_into_try.rs
@@ -0,0 +1,41 @@
+#![feature(coverage_attribute)]
+// compile-flags: --edition=2021
+
+// Regression test for inconsistent handling of function signature spans that
+// are followed by code using the `?` operator.
+//
+// For each of these similar functions, the line containing the function
+// signature should be handled in the same way.
+
+fn a() -> Option<i32>
+{
+ Some(7i32);
+ Some(0)
+}
+
+fn b() -> Option<i32>
+{
+ Some(7i32)?;
+ Some(0)
+}
+
+fn c() -> Option<i32>
+{
+ let _ = Some(7i32)?;
+ Some(0)
+}
+
+fn d() -> Option<i32>
+{
+ let _: () = ();
+ Some(7i32)?;
+ Some(0)
+}
+
+#[coverage(off)]
+fn main() {
+ a();
+ b();
+ c();
+ d();
+}
diff --git a/tests/coverage/generics.cov-map b/tests/coverage/generics.cov-map
new file mode 100644
index 000000000..6079a433c
--- /dev/null
+++ b/tests/coverage/generics.cov-map
@@ -0,0 +1,45 @@
+Function name: <generics::Firework<f64> as core::ops::drop::Drop>::drop
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6)
+
+Function name: <generics::Firework<f64>>::set_strength
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6)
+
+Function name: <generics::Firework<i32> as core::ops::drop::Drop>::drop
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6)
+
+Function name: <generics::Firework<i32>>::set_strength
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6)
+
+Function name: generics::main
+Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 16, 01, 08, 0c, 05, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 22, 1) to (start + 8, 12)
+- Code(Counter(1)) at (prev + 9, 9) to (start + 1, 22)
+- Code(Zero) at (prev + 2, 6) to (start + 4, 11)
+- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2)
+ = (c1 + Zero)
+
diff --git a/tests/coverage/generics.coverage b/tests/coverage/generics.coverage
new file mode 100644
index 000000000..098391835
--- /dev/null
+++ b/tests/coverage/generics.coverage
@@ -0,0 +1,67 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |// failure-status: 1
+ LL| |
+ LL| |struct Firework<T> where T: Copy + std::fmt::Display {
+ LL| | strength: T,
+ LL| |}
+ LL| |
+ LL| |impl<T> Firework<T> where T: Copy + std::fmt::Display {
+ LL| | #[inline(always)]
+ LL| 3| fn set_strength(&mut self, new_strength: T) {
+ LL| 3| self.strength = new_strength;
+ LL| 3| }
+ ------------------
+ | <generics::Firework<f64>>::set_strength:
+ | LL| 2| fn set_strength(&mut self, new_strength: T) {
+ | LL| 2| self.strength = new_strength;
+ | LL| 2| }
+ ------------------
+ | <generics::Firework<i32>>::set_strength:
+ | LL| 1| fn set_strength(&mut self, new_strength: T) {
+ | LL| 1| self.strength = new_strength;
+ | LL| 1| }
+ ------------------
+ LL| |}
+ LL| |
+ LL| |impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display {
+ LL| | #[inline(always)]
+ LL| 2| fn drop(&mut self) {
+ LL| 2| println!("BOOM times {}!!!", self.strength);
+ LL| 2| }
+ ------------------
+ | <generics::Firework<f64> as core::ops::drop::Drop>::drop:
+ | LL| 1| fn drop(&mut self) {
+ | LL| 1| println!("BOOM times {}!!!", self.strength);
+ | LL| 1| }
+ ------------------
+ | <generics::Firework<i32> as core::ops::drop::Drop>::drop:
+ | LL| 1| fn drop(&mut self) {
+ | LL| 1| println!("BOOM times {}!!!", self.strength);
+ | LL| 1| }
+ ------------------
+ LL| |}
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| let mut firecracker = Firework { strength: 1 };
+ LL| 1| firecracker.set_strength(2);
+ LL| 1|
+ LL| 1| let mut tnt = Firework { strength: 100.1 };
+ LL| 1| tnt.set_strength(200.1);
+ LL| 1| tnt.set_strength(300.3);
+ LL| 1|
+ LL| 1| if true {
+ LL| 1| println!("Exiting with error...");
+ LL| 1| return Err(1);
+ LL| 0| }
+ LL| 0|
+ LL| 0| let _ = Firework { strength: 1000 };
+ LL| 0|
+ LL| 0| Ok(())
+ LL| 1|}
+ LL| |
+ LL| |// Expected program output:
+ LL| |// Exiting with error...
+ LL| |// BOOM times 100!!!
+ LL| |// BOOM times 1!!!
+ LL| |// Error: 1
+
diff --git a/tests/coverage/generics.rs b/tests/coverage/generics.rs
new file mode 100644
index 000000000..bf4c2d8d6
--- /dev/null
+++ b/tests/coverage/generics.rs
@@ -0,0 +1,44 @@
+#![allow(unused_assignments)]
+// failure-status: 1
+
+struct Firework<T> where T: Copy + std::fmt::Display {
+ strength: T,
+}
+
+impl<T> Firework<T> where T: Copy + std::fmt::Display {
+ #[inline(always)]
+ fn set_strength(&mut self, new_strength: T) {
+ self.strength = new_strength;
+ }
+}
+
+impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display {
+ #[inline(always)]
+ fn drop(&mut self) {
+ println!("BOOM times {}!!!", self.strength);
+ }
+}
+
+fn main() -> Result<(), u8> {
+ let mut firecracker = Firework { strength: 1 };
+ firecracker.set_strength(2);
+
+ let mut tnt = Firework { strength: 100.1 };
+ tnt.set_strength(200.1);
+ tnt.set_strength(300.3);
+
+ if true {
+ println!("Exiting with error...");
+ return Err(1);
+ }
+
+ let _ = Firework { strength: 1000 };
+
+ Ok(())
+}
+
+// Expected program output:
+// Exiting with error...
+// BOOM times 100!!!
+// BOOM times 1!!!
+// Error: 1
diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map
new file mode 100644
index 000000000..391a69e0e
--- /dev/null
+++ b/tests/coverage/if.cov-map
@@ -0,0 +1,15 @@
+Function name: if::main
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 03, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 3, 1) to (start + 18, 16)
+- Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6)
+- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
diff --git a/tests/coverage/if.coverage b/tests/coverage/if.coverage
new file mode 100644
index 000000000..2e6845190
--- /dev/null
+++ b/tests/coverage/if.coverage
@@ -0,0 +1,30 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let
+ LL| 1| is_true
+ LL| 1| =
+ LL| 1| std::env::args().len()
+ LL| 1| ==
+ LL| 1| 1
+ LL| 1| ;
+ LL| 1| let
+ LL| 1| mut
+ LL| 1| countdown
+ LL| 1| =
+ LL| 1| 0
+ LL| 1| ;
+ LL| 1| if
+ LL| 1| is_true
+ LL| 1| {
+ LL| 1| countdown
+ LL| 1| =
+ LL| 1| 10
+ LL| 1| ;
+ LL| 1| }
+ ^0
+ LL| 1|}
+
diff --git a/tests/coverage/if.rs b/tests/coverage/if.rs
new file mode 100644
index 000000000..8ad5042ff
--- /dev/null
+++ b/tests/coverage/if.rs
@@ -0,0 +1,28 @@
+#![allow(unused_assignments, unused_variables)]
+
+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
+ countdown
+ =
+ 0
+ ;
+ if
+ is_true
+ {
+ countdown
+ =
+ 10
+ ;
+ }
+}
diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map
new file mode 100644
index 000000000..da692ca3a
--- /dev/null
+++ b/tests/coverage/if_else.cov-map
@@ -0,0 +1,25 @@
+Function name: if_else::main
+Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 03, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 1b, 06, 09, 00, 10, 09, 01, 05, 05, 06, 16, 07, 05, 05, 06, 13, 06, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 7
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub)
+- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 7
+- Code(Counter(0)) at (prev + 3, 1) to (start + 8, 16)
+- Code(Counter(1)) at (prev + 9, 5) to (start + 5, 6)
+- Code(Expression(0, Sub)) at (prev + 8, 9) to (start + 2, 16)
+ = (c0 - c1)
+- Code(Expression(6, Add)) at (prev + 6, 9) to (start + 0, 16)
+ = (c1 + (c0 - c1))
+- Code(Counter(2)) at (prev + 1, 5) to (start + 5, 6)
+- Code(Expression(5, Sub)) at (prev + 7, 5) to (start + 5, 6)
+ = ((c1 + (c0 - c1)) - c2)
+- Code(Expression(4, Add)) at (prev + 6, 1) to (start + 0, 2)
+ = (c2 + ((c1 + (c0 - c1)) - c2))
+
diff --git a/tests/coverage/if_else.coverage b/tests/coverage/if_else.coverage
new file mode 100644
index 000000000..0274401f0
--- /dev/null
+++ b/tests/coverage/if_else.coverage
@@ -0,0 +1,41 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let mut countdown = 0;
+ LL| 1| if
+ LL| 1| is_true
+ LL| 1| {
+ LL| 1| countdown
+ LL| 1| =
+ LL| 1| 10
+ LL| 1| ;
+ LL| 1| }
+ LL| | else // Note coverage region difference without semicolon
+ LL| | {
+ LL| 0| countdown
+ LL| 0| =
+ LL| 0| 100
+ LL| | }
+ LL| |
+ LL| | if
+ LL| 1| is_true
+ LL| 1| {
+ LL| 1| countdown
+ LL| 1| =
+ LL| 1| 10
+ LL| 1| ;
+ LL| 1| }
+ LL| | else
+ LL| 0| {
+ LL| 0| countdown
+ LL| 0| =
+ LL| 0| 100
+ LL| 0| ;
+ LL| 0| }
+ LL| 1|}
+
diff --git a/tests/coverage/if_else.rs b/tests/coverage/if_else.rs
new file mode 100644
index 000000000..3244e1e3a
--- /dev/null
+++ b/tests/coverage/if_else.rs
@@ -0,0 +1,40 @@
+#![allow(unused_assignments, unused_variables)]
+
+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 countdown = 0;
+ if
+ is_true
+ {
+ countdown
+ =
+ 10
+ ;
+ }
+ else // Note coverage region difference without semicolon
+ {
+ countdown
+ =
+ 100
+ }
+
+ if
+ is_true
+ {
+ countdown
+ =
+ 10
+ ;
+ }
+ else
+ {
+ countdown
+ =
+ 100
+ ;
+ }
+}
diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map
new file mode 100644
index 000000000..958b423f2
--- /dev/null
+++ b/tests/coverage/inline-dead.cov-map
@@ -0,0 +1,45 @@
+Function name: inline_dead::dead (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+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, 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 = 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 - Zero)
+- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = (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]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 13)
+- 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, 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 = 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)
+ = (Zero + (c0 - Zero))
+
diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/inline-dead.coverage
new file mode 100644
index 000000000..de96aa17a
--- /dev/null
+++ b/tests/coverage/inline-dead.coverage
@@ -0,0 +1,28 @@
+ LL| |// Regression test for issue #98833.
+ LL| |// compile-flags: -Zinline-mir -Cdebug-assertions=off
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| println!("{}", live::<false>());
+ LL| 1|
+ LL| 1| let f = |x: bool| {
+ LL| | debug_assert!(
+ LL| 0| x
+ LL| | );
+ LL| 1| };
+ LL| 1| f(false);
+ LL| 1|}
+ LL| |
+ LL| |#[inline]
+ LL| 1|fn live<const B: bool>() -> u32 {
+ LL| 1| if B {
+ LL| 0| dead()
+ LL| | } else {
+ LL| 1| 0
+ LL| | }
+ LL| 1|}
+ LL| |
+ LL| |#[inline]
+ LL| 0|fn dead() -> u32 {
+ LL| 0| 42
+ LL| 0|}
+
diff --git a/tests/coverage/inline-dead.rs b/tests/coverage/inline-dead.rs
new file mode 100644
index 000000000..854fa0629
--- /dev/null
+++ b/tests/coverage/inline-dead.rs
@@ -0,0 +1,27 @@
+// Regression test for issue #98833.
+// compile-flags: -Zinline-mir -Cdebug-assertions=off
+
+fn main() {
+ println!("{}", live::<false>());
+
+ let f = |x: bool| {
+ debug_assert!(
+ x
+ );
+ };
+ f(false);
+}
+
+#[inline]
+fn live<const B: bool>() -> u32 {
+ if B {
+ dead()
+ } else {
+ 0
+ }
+}
+
+#[inline]
+fn dead() -> u32 {
+ 42
+}
diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map
new file mode 100644
index 000000000..72b10fd0c
--- /dev/null
+++ b/tests/coverage/inline.cov-map
@@ -0,0 +1,78 @@
+Function name: inline::display::<char>
+Raw bytes (33): 0x[01, 01, 02, 01, 05, 03, 05, 05, 01, 29, 01, 00, 22, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 10, 05, 00, 11, 02, 06, 06, 03, 05, 01, 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)
+Number of file 0 mappings: 5
+- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 34)
+- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10)
+- Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 16)
+ = (c0 + c1)
+- Code(Counter(1)) at (prev + 0, 17) to (start + 2, 6)
+- Code(Expression(1, Sub)) at (prev + 3, 5) to (start + 1, 2)
+ = ((c0 + c1) - c1)
+
+Function name: inline::error
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 49, 1) to (start + 2, 2)
+
+Function name: inline::length::<char>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 2)
+
+Function name: inline::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 5, 1) to (start + 2, 2)
+
+Function name: inline::permutate::<char>
+Raw bytes (52): 0x[01, 01, 04, 01, 05, 02, 0d, 05, 0f, 09, 0d, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 11, 01, 0d, 00, 0e, 06, 00, 12, 00, 16, 11, 00, 17, 04, 0a, 0d, 05, 0c, 02, 06, 0b, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Expression(0, Sub), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(1), rhs = Expression(3, Add)
+- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 8
+- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 14)
+- Code(Counter(1)) at (prev + 2, 15) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 15) to (start + 0, 20)
+ = (c0 - c1)
+- Code(Counter(4)) at (prev + 1, 13) to (start + 0, 14)
+- Code(Expression(1, Sub)) at (prev + 0, 18) to (start + 0, 22)
+ = ((c0 - c1) - c3)
+- Code(Counter(4)) at (prev + 0, 23) to (start + 4, 10)
+- Code(Counter(3)) at (prev + 5, 12) to (start + 2, 6)
+- Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
+ = (c1 + (c2 + c3))
+
+Function name: inline::permutations::<char>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 03, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 10, 1) to (start + 3, 2)
+
+Function name: inline::swap::<char>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 04, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 35, 1) to (start + 4, 2)
+
diff --git a/tests/coverage/inline.coverage b/tests/coverage/inline.coverage
new file mode 100644
index 000000000..6efd9a083
--- /dev/null
+++ b/tests/coverage/inline.coverage
@@ -0,0 +1,54 @@
+ LL| |// compile-flags: -Zinline-mir
+ LL| |
+ LL| |use std::fmt::Display;
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| permutations(&['a', 'b', 'c']);
+ LL| 1|}
+ LL| |
+ LL| |#[inline(always)]
+ LL| 1|fn permutations<T: Copy + Display>(xs: &[T]) {
+ LL| 1| let mut ys = xs.to_owned();
+ LL| 1| permutate(&mut ys, 0);
+ LL| 1|}
+ LL| |
+ LL| 16|fn permutate<T: Copy + Display>(xs: &mut [T], k: usize) {
+ LL| 16| let n = length(xs);
+ LL| 16| if k == n {
+ LL| 6| display(xs);
+ LL| 10| } else if k < n {
+ LL| 15| for i in k..n {
+ ^10
+ LL| 15| swap(xs, i, k);
+ LL| 15| permutate(xs, k + 1);
+ LL| 15| swap(xs, i, k);
+ LL| 15| }
+ LL| 0| } else {
+ LL| 0| error();
+ LL| 0| }
+ LL| 16|}
+ LL| |
+ LL| 16|fn length<T>(xs: &[T]) -> usize {
+ LL| 16| xs.len()
+ LL| 16|}
+ LL| |
+ LL| |#[inline]
+ LL| 30|fn swap<T: Copy>(xs: &mut [T], i: usize, j: usize) {
+ LL| 30| let t = xs[i];
+ LL| 30| xs[i] = xs[j];
+ LL| 30| xs[j] = t;
+ LL| 30|}
+ LL| |
+ LL| 6|fn display<T: Display>(xs: &[T]) {
+ LL| 24| for x in xs {
+ ^18
+ LL| 18| print!("{}", x);
+ LL| 18| }
+ LL| 6| println!();
+ LL| 6|}
+ LL| |
+ LL| |#[inline(always)]
+ LL| 0|fn error() {
+ LL| 0| panic!("error");
+ LL| 0|}
+
diff --git a/tests/coverage/inline.rs b/tests/coverage/inline.rs
new file mode 100644
index 000000000..9cfab9ddb
--- /dev/null
+++ b/tests/coverage/inline.rs
@@ -0,0 +1,51 @@
+// compile-flags: -Zinline-mir
+
+use std::fmt::Display;
+
+fn main() {
+ permutations(&['a', 'b', 'c']);
+}
+
+#[inline(always)]
+fn permutations<T: Copy + Display>(xs: &[T]) {
+ let mut ys = xs.to_owned();
+ permutate(&mut ys, 0);
+}
+
+fn permutate<T: Copy + Display>(xs: &mut [T], k: usize) {
+ let n = length(xs);
+ if k == n {
+ display(xs);
+ } else if k < n {
+ for i in k..n {
+ swap(xs, i, k);
+ permutate(xs, k + 1);
+ swap(xs, i, k);
+ }
+ } else {
+ error();
+ }
+}
+
+fn length<T>(xs: &[T]) -> usize {
+ xs.len()
+}
+
+#[inline]
+fn swap<T: Copy>(xs: &mut [T], i: usize, j: usize) {
+ let t = xs[i];
+ xs[i] = xs[j];
+ xs[j] = t;
+}
+
+fn display<T: Display>(xs: &[T]) {
+ for x in xs {
+ print!("{}", x);
+ }
+ println!();
+}
+
+#[inline(always)]
+fn error() {
+ panic!("error");
+}
diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map
new file mode 100644
index 000000000..3f39d74ef
--- /dev/null
+++ b/tests/coverage/inner_items.cov-map
@@ -0,0 +1,49 @@
+Function name: <inner_items::main::InStruct as inner_items::main::InTrait>::default_trait_func
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 09, 03, 0a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 33, 9) to (start + 3, 10)
+
+Function name: <inner_items::main::InStruct as inner_items::main::InTrait>::trait_func
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 28, 09, 03, 0a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10)
+
+Function name: inner_items::main
+Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1b, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 16, 02, 06, 00, 07, 13, 02, 09, 05, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 7
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub)
+- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 7
+- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15)
+- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(6, Add)) at (prev + 36, 8) to (start + 0, 15)
+ = (c1 + (c0 - c1))
+- Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6)
+- Code(Expression(5, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = ((c1 + (c0 - c1)) - c2)
+- Code(Expression(4, Add)) at (prev + 2, 9) to (start + 5, 2)
+ = (c2 + ((c1 + (c0 - c1)) - c2))
+
+Function name: inner_items::main::in_func
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 18, 5) to (start + 4, 6)
+
diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/inner_items.coverage
new file mode 100644
index 000000000..65493bcd9
--- /dev/null
+++ b/tests/coverage/inner_items.coverage
@@ -0,0 +1,60 @@
+ LL| |#![allow(unused_assignments, unused_variables, dead_code)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let mut countdown = 0;
+ LL| 1| if is_true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| |
+ LL| | mod in_mod {
+ LL| | const IN_MOD_CONST: u32 = 1000;
+ LL| | }
+ LL| |
+ LL| 3| fn in_func(a: u32) {
+ LL| 3| let b = 1;
+ LL| 3| let c = a + b;
+ LL| 3| println!("c = {}", c)
+ LL| 3| }
+ LL| |
+ LL| | struct InStruct {
+ LL| | in_struct_field: u32,
+ LL| | }
+ LL| |
+ LL| | const IN_CONST: u32 = 1234;
+ LL| |
+ LL| | trait InTrait {
+ LL| | fn trait_func(&mut self, incr: u32);
+ LL| |
+ LL| 1| fn default_trait_func(&mut self) {
+ LL| 1| in_func(IN_CONST);
+ LL| 1| self.trait_func(IN_CONST);
+ LL| 1| }
+ LL| | }
+ LL| |
+ LL| | impl InTrait for InStruct {
+ LL| 1| fn trait_func(&mut self, incr: u32) {
+ LL| 1| self.in_struct_field += incr;
+ LL| 1| in_func(self.in_struct_field);
+ LL| 1| }
+ LL| | }
+ LL| |
+ LL| | type InType = String;
+ LL| |
+ LL| 1| if is_true {
+ LL| 1| in_func(countdown);
+ LL| 1| }
+ ^0
+ LL| |
+ LL| 1| let mut val = InStruct {
+ LL| 1| in_struct_field: 101,
+ LL| 1| };
+ LL| 1|
+ LL| 1| val.default_trait_func();
+ LL| 1|}
+
diff --git a/tests/coverage/inner_items.rs b/tests/coverage/inner_items.rs
new file mode 100644
index 000000000..bcb62b303
--- /dev/null
+++ b/tests/coverage/inner_items.rs
@@ -0,0 +1,57 @@
+#![allow(unused_assignments, unused_variables, dead_code)]
+
+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 countdown = 0;
+ if is_true {
+ countdown = 10;
+ }
+
+ mod in_mod {
+ const IN_MOD_CONST: u32 = 1000;
+ }
+
+ fn in_func(a: u32) {
+ let b = 1;
+ let c = a + b;
+ println!("c = {}", c)
+ }
+
+ struct InStruct {
+ in_struct_field: u32,
+ }
+
+ const IN_CONST: u32 = 1234;
+
+ trait InTrait {
+ fn trait_func(&mut self, incr: u32);
+
+ fn default_trait_func(&mut self) {
+ in_func(IN_CONST);
+ self.trait_func(IN_CONST);
+ }
+ }
+
+ impl InTrait for InStruct {
+ fn trait_func(&mut self, incr: u32) {
+ self.in_struct_field += incr;
+ in_func(self.in_struct_field);
+ }
+ }
+
+ type InType = String;
+
+ if is_true {
+ in_func(countdown);
+ }
+
+ let mut val = InStruct {
+ in_struct_field: 101,
+ };
+
+ val.default_trait_func();
+}
diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map
new file mode 100644
index 000000000..f5db3a897
--- /dev/null
+++ b/tests/coverage/issue-83601.cov-map
@@ -0,0 +1,28 @@
+Function name: <issue_83601::Foo as core::cmp::PartialEq>::eq
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 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 + 3, 17) to (start + 0, 26)
+
+Function name: <issue_83601::Foo as core::fmt::Debug>::fmt
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 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 + 3, 10) to (start + 0, 15)
+
+Function name: issue_83601::main
+Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 28)
+- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28)
+- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2)
+ = (c1 - c2)
+
diff --git a/tests/coverage/issue-83601.coverage b/tests/coverage/issue-83601.coverage
new file mode 100644
index 000000000..7995332ca
--- /dev/null
+++ b/tests/coverage/issue-83601.coverage
@@ -0,0 +1,16 @@
+ LL| |// Shows that rust-lang/rust/83601 is resolved
+ LL| |
+ LL| 3|#[derive(Debug, PartialEq, Eq)]
+ ^2
+ LL| |struct Foo(u32);
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let bar = Foo(1);
+ LL| 1| assert_eq!(bar, Foo(1));
+ LL| 1| let baz = Foo(0);
+ LL| 1| assert_ne!(baz, Foo(1));
+ LL| 1| println!("{:?}", Foo(1));
+ LL| 1| println!("{:?}", bar);
+ LL| 1| println!("{:?}", baz);
+ LL| 1|}
+
diff --git a/tests/coverage/issue-83601.rs b/tests/coverage/issue-83601.rs
new file mode 100644
index 000000000..0b72a8194
--- /dev/null
+++ b/tests/coverage/issue-83601.rs
@@ -0,0 +1,14 @@
+// Shows that rust-lang/rust/83601 is resolved
+
+#[derive(Debug, PartialEq, Eq)]
+struct Foo(u32);
+
+fn main() {
+ let bar = Foo(1);
+ assert_eq!(bar, Foo(1));
+ let baz = Foo(0);
+ assert_ne!(baz, Foo(1));
+ println!("{:?}", Foo(1));
+ println!("{:?}", bar);
+ println!("{:?}", baz);
+}
diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map
new file mode 100644
index 000000000..82582b309
--- /dev/null
+++ b/tests/coverage/issue-84561.cov-map
@@ -0,0 +1,232 @@
+Function name: <issue_84561::Foo as core::cmp::PartialEq>::eq
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 0a, 00, 13]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19)
+
+Function name: <issue_84561::Foo as core::fmt::Debug>::fmt
+Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 88, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 136, 5) to (start + 1, 37)
+- Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38)
+- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 0, 6)
+ = (c1 + (c0 - c1))
+
+Function name: issue_84561::main
+Raw bytes (10): 0x[01, 01, 00, 01, 01, b2, 01, 01, 04, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 178, 1) to (start + 4, 2)
+
+Function name: issue_84561::test1
+Raw bytes (78): 0x[01, 01, 0e, 05, 06, 01, 05, 09, 36, 03, 09, 0d, 2e, 33, 0d, 09, 36, 03, 09, 11, 26, 2b, 11, 0d, 2e, 33, 0d, 09, 36, 03, 09, 09, 01, 98, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 03, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 33, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 2b, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 23, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 14
+- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 2 operands: lhs = Counter(2), rhs = Expression(13, Sub)
+- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 4 operands: lhs = Counter(3), rhs = Expression(11, Sub)
+- expression 5 operands: lhs = Expression(12, Add), rhs = Counter(3)
+- expression 6 operands: lhs = Counter(2), rhs = Expression(13, Sub)
+- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 8 operands: lhs = Counter(4), rhs = Expression(9, Sub)
+- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(4)
+- expression 10 operands: lhs = Counter(3), rhs = Expression(11, Sub)
+- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(2), rhs = Expression(13, Sub)
+- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(2)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 152, 1) to (start + 1, 11)
+- Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30)
+- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 11)
+ = (c1 + (c0 - c1))
+- Code(Counter(2)) at (prev + 0, 12) to (start + 0, 30)
+- Code(Expression(12, Add)) at (prev + 1, 13) to (start + 1, 11)
+ = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 30)
+- Code(Expression(10, Add)) at (prev + 1, 5) to (start + 3, 11)
+ = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30)
+- Code(Expression(8, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+
+Function name: issue_84561::test2
+Raw bytes (24): 0x[01, 01, 02, 05, 06, 01, 05, 03, 01, ae, 01, 01, 01, 10, 05, 01, 11, 00, 23, 03, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 174, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35)
+- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: issue_84561::test2::call_print
+Raw bytes (10): 0x[01, 01, 00, 01, 01, a5, 01, 09, 02, 0a]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 165, 9) to (start + 2, 10)
+
+Function name: issue_84561::test3
+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 = Zero
+- expression 2 operands: lhs = Counter(5), rhs = Counter(6)
+- 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 = 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 = 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 = 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 = Zero
+- expression 21 operands: lhs = Expression(36, Sub), rhs = Counter(21)
+- 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 = 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 = 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 = 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)
+- expression 40 operands: lhs = Expression(64, Sub), rhs = Counter(28)
+- expression 41 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 42 operands: lhs = Counter(28), rhs = Expression(63, Sub)
+- expression 43 operands: lhs = Expression(64, Sub), rhs = Counter(28)
+- expression 44 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 45 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 46 operands: lhs = Expression(64, Sub), rhs = Counter(28)
+- expression 47 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 48 operands: lhs = Expression(62, Add), rhs = Counter(30)
+- expression 49 operands: lhs = Counter(28), rhs = Expression(63, Sub)
+- expression 50 operands: lhs = Expression(64, Sub), rhs = Counter(28)
+- expression 51 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 52 operands: lhs = Expression(60, Add), rhs = Counter(31)
+- expression 53 operands: lhs = Counter(29), rhs = Expression(61, Sub)
+- expression 54 operands: lhs = Expression(62, Add), rhs = Counter(30)
+- 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 = 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)
+- expression 62 operands: lhs = Counter(28), rhs = Expression(63, Sub)
+- expression 63 operands: lhs = Expression(64, Sub), rhs = Counter(28)
+- expression 64 operands: lhs = Counter(26), rhs = Counter(27)
+Number of file 0 mappings: 51
+- Code(Counter(0)) at (prev + 6, 1) to (start + 3, 28)
+- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28)
+- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 4, 31)
+ = (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 - 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) - 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 - 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 - 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 - 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)
+- Code(Counter(17)) at (prev + 1, 9) to (start + 3, 10)
+- 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 - 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 - 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 - Zero) + c21) - c23))
+- Code(Expression(35, Add)) at (prev + 1, 12) to (start + 0, 19)
+ = ((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 - Zero) + c21) - c23)
+- Code(Expression(32, Sub)) at (prev + 4, 5) to (start + 2, 19)
+ = ((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 - 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)
+- Code(Counter(27)) at (prev + 1, 13) to (start + 3, 14)
+- Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19)
+- Code(Expression(62, Add)) at (prev + 2, 13) to (start + 0, 23)
+ = (c28 + ((c26 - c27) - c28))
+- Code(Expression(64, Sub)) at (prev + 1, 20) to (start + 0, 27)
+ = (c26 - c27)
+- Code(Counter(28)) at (prev + 1, 21) to (start + 0, 27)
+- Code(Expression(63, Sub)) at (prev + 2, 21) to (start + 0, 27)
+ = ((c26 - c27) - c28)
+- Code(Expression(61, Sub)) at (prev + 4, 13) to (start + 0, 19)
+ = ((c28 + ((c26 - c27) - c28)) - c30)
+- Code(Counter(31)) at (prev + 3, 9) to (start + 0, 25)
+- 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) - 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/issue-84561.coverage b/tests/coverage/issue-84561.coverage
new file mode 100644
index 000000000..e693866e2
--- /dev/null
+++ b/tests/coverage/issue-84561.coverage
@@ -0,0 +1,189 @@
+ LL| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+ LL| |
+ LL| |// failure-status: 101
+ LL| 21|#[derive(PartialEq, Eq)]
+ LL| |struct Foo(u32);
+ LL| 1|fn test3() {
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1| let bar = Foo(1);
+ LL| 1| assert_eq!(bar, Foo(1));
+ LL| 1| let baz = Foo(0);
+ LL| 1| assert_ne!(baz, Foo(1));
+ LL| 1| println!("{:?}", Foo(1));
+ LL| 1| println!("{:?}", bar);
+ LL| 1| println!("{:?}", baz);
+ LL| 1|
+ LL| 1| assert_eq!(Foo(1), Foo(1));
+ LL| 1| assert_ne!(Foo(0), Foo(1));
+ LL| 1| assert_eq!(Foo(2), Foo(2));
+ LL| 1| let bar = Foo(0);
+ LL| 1| assert_ne!(bar, Foo(3));
+ LL| 1| assert_ne!(Foo(0), Foo(4));
+ LL| 1| assert_eq!(Foo(3), Foo(3), "with a message");
+ ^0
+ LL| 1| println!("{:?}", bar);
+ LL| 1| println!("{:?}", Foo(1));
+ LL| 1|
+ LL| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+ ^0 ^0 ^0
+ LL| 1| assert_ne!(
+ LL| | Foo(0)
+ LL| | ,
+ LL| | Foo(5)
+ LL| | ,
+ LL| 0| "{}"
+ LL| 0| ,
+ LL| 0| if
+ LL| 0| is_true
+ LL| | {
+ LL| 0| "true message"
+ LL| | } else {
+ LL| 0| "false message"
+ LL| | }
+ LL| | );
+ LL| |
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| assert_eq!(
+ LL| 1| Foo(1),
+ LL| 1| Foo(1)
+ LL| 1| );
+ LL| 1| assert_ne!(
+ LL| 1| Foo(0),
+ LL| 1| Foo(1)
+ LL| 1| );
+ LL| 1| assert_eq!(
+ LL| 1| Foo(2),
+ LL| 1| Foo(2)
+ LL| 1| );
+ LL| 1| let bar = Foo(1);
+ LL| 1| assert_ne!(
+ LL| 1| bar,
+ LL| 1| Foo(3)
+ LL| 1| );
+ LL| 1| if is_true {
+ LL| 1| assert_ne!(
+ LL| 1| Foo(0),
+ LL| 1| Foo(4)
+ LL| 1| );
+ LL| | } else {
+ LL| 0| assert_eq!(
+ LL| 0| Foo(3),
+ LL| 0| Foo(3)
+ LL| 0| );
+ LL| | }
+ LL| 1| if is_true {
+ LL| 1| assert_ne!(
+ LL| | Foo(0),
+ LL| | Foo(4),
+ LL| 0| "with a message"
+ LL| | );
+ LL| | } else {
+ LL| 0| assert_eq!(
+ LL| | Foo(3),
+ LL| | Foo(3),
+ LL| 0| "with a message"
+ LL| | );
+ LL| | }
+ LL| 1| assert_ne!(
+ LL| 1| if is_true {
+ LL| 1| Foo(0)
+ LL| | } else {
+ LL| 0| Foo(1)
+ LL| | },
+ LL| | Foo(5)
+ LL| | );
+ LL| 1| assert_ne!(
+ LL| 1| Foo(5),
+ LL| 1| if is_true {
+ LL| 1| Foo(0)
+ LL| | } else {
+ LL| 0| Foo(1)
+ LL| | }
+ LL| | );
+ LL| 1| assert_ne!(
+ LL| 1| if is_true {
+ LL| 1| assert_eq!(
+ LL| 1| Foo(3),
+ LL| 1| Foo(3)
+ LL| 1| );
+ LL| 1| Foo(0)
+ LL| | } else {
+ LL| 0| assert_ne!(
+ LL| 0| if is_true {
+ LL| 0| Foo(0)
+ LL| | } else {
+ LL| 0| Foo(1)
+ LL| | },
+ LL| | Foo(5)
+ LL| | );
+ LL| 0| Foo(1)
+ LL| | },
+ LL| | Foo(5),
+ LL| 0| "with a message"
+ LL| | );
+ LL| 1| assert_eq!(
+ LL| | Foo(1),
+ LL| | Foo(3),
+ LL| 1| "this assert should fail"
+ LL| | );
+ LL| 0| assert_eq!(
+ LL| | Foo(3),
+ LL| | Foo(3),
+ LL| 0| "this assert should not be reached"
+ LL| | );
+ LL| 0|}
+ LL| |
+ LL| |impl std::fmt::Debug for Foo {
+ LL| 7| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ LL| 7| write!(f, "try and succeed")?;
+ ^0
+ LL| 7| Ok(())
+ LL| 7| }
+ LL| |}
+ LL| |
+ LL| |static mut DEBUG_LEVEL_ENABLED: bool = false;
+ LL| |
+ LL| |macro_rules! debug {
+ LL| | ($($arg:tt)+) => (
+ LL| | if unsafe { DEBUG_LEVEL_ENABLED } {
+ LL| | println!($($arg)+);
+ LL| | }
+ LL| | );
+ LL| |}
+ LL| |
+ LL| 1|fn test1() {
+ LL| 1| debug!("debug is enabled");
+ ^0
+ LL| 1| debug!("debug is enabled");
+ ^0
+ LL| 1| let _ = 0;
+ LL| 1| debug!("debug is enabled");
+ ^0
+ LL| 1| unsafe {
+ LL| 1| DEBUG_LEVEL_ENABLED = true;
+ LL| 1| }
+ LL| 1| debug!("debug is enabled");
+ LL| 1|}
+ LL| |
+ LL| |macro_rules! call_debug {
+ LL| | ($($arg:tt)+) => (
+ LL| 1| fn call_print(s: &str) {
+ LL| 1| print!("{}", s);
+ LL| 1| }
+ LL| |
+ LL| | call_print("called from call_debug: ");
+ LL| | debug!($($arg)+);
+ LL| | );
+ LL| |}
+ LL| |
+ LL| 1|fn test2() {
+ LL| 1| call_debug!("debug is enabled");
+ LL| 1|}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| test1();
+ LL| 1| test2();
+ LL| 1| test3();
+ LL| 1|}
+
diff --git a/tests/coverage/issue-84561.rs b/tests/coverage/issue-84561.rs
new file mode 100644
index 000000000..facf5b5b4
--- /dev/null
+++ b/tests/coverage/issue-84561.rs
@@ -0,0 +1,182 @@
+// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+
+// failure-status: 101
+#[derive(PartialEq, Eq)]
+struct Foo(u32);
+fn test3() {
+ let is_true = std::env::args().len() == 1;
+ let bar = Foo(1);
+ assert_eq!(bar, Foo(1));
+ let baz = Foo(0);
+ assert_ne!(baz, Foo(1));
+ println!("{:?}", Foo(1));
+ println!("{:?}", bar);
+ println!("{:?}", baz);
+
+ assert_eq!(Foo(1), Foo(1));
+ assert_ne!(Foo(0), Foo(1));
+ assert_eq!(Foo(2), Foo(2));
+ let bar = Foo(0);
+ assert_ne!(bar, Foo(3));
+ assert_ne!(Foo(0), Foo(4));
+ assert_eq!(Foo(3), Foo(3), "with a message");
+ println!("{:?}", bar);
+ println!("{:?}", Foo(1));
+
+ assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+ assert_ne!(
+ Foo(0)
+ ,
+ Foo(5)
+ ,
+ "{}"
+ ,
+ if
+ is_true
+ {
+ "true message"
+ } else {
+ "false message"
+ }
+ );
+
+ let is_true = std::env::args().len() == 1;
+
+ assert_eq!(
+ Foo(1),
+ Foo(1)
+ );
+ assert_ne!(
+ Foo(0),
+ Foo(1)
+ );
+ assert_eq!(
+ Foo(2),
+ Foo(2)
+ );
+ let bar = Foo(1);
+ assert_ne!(
+ bar,
+ Foo(3)
+ );
+ if is_true {
+ assert_ne!(
+ Foo(0),
+ Foo(4)
+ );
+ } else {
+ assert_eq!(
+ Foo(3),
+ Foo(3)
+ );
+ }
+ if is_true {
+ assert_ne!(
+ Foo(0),
+ Foo(4),
+ "with a message"
+ );
+ } else {
+ assert_eq!(
+ Foo(3),
+ Foo(3),
+ "with a message"
+ );
+ }
+ assert_ne!(
+ if is_true {
+ Foo(0)
+ } else {
+ Foo(1)
+ },
+ Foo(5)
+ );
+ assert_ne!(
+ Foo(5),
+ if is_true {
+ Foo(0)
+ } else {
+ Foo(1)
+ }
+ );
+ assert_ne!(
+ if is_true {
+ assert_eq!(
+ Foo(3),
+ Foo(3)
+ );
+ Foo(0)
+ } else {
+ assert_ne!(
+ if is_true {
+ Foo(0)
+ } else {
+ Foo(1)
+ },
+ Foo(5)
+ );
+ Foo(1)
+ },
+ Foo(5),
+ "with a message"
+ );
+ assert_eq!(
+ Foo(1),
+ Foo(3),
+ "this assert should fail"
+ );
+ assert_eq!(
+ Foo(3),
+ Foo(3),
+ "this assert should not be reached"
+ );
+}
+
+impl std::fmt::Debug for Foo {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "try and succeed")?;
+ Ok(())
+ }
+}
+
+static mut DEBUG_LEVEL_ENABLED: bool = false;
+
+macro_rules! debug {
+ ($($arg:tt)+) => (
+ if unsafe { DEBUG_LEVEL_ENABLED } {
+ println!($($arg)+);
+ }
+ );
+}
+
+fn test1() {
+ debug!("debug is enabled");
+ debug!("debug is enabled");
+ let _ = 0;
+ debug!("debug is enabled");
+ unsafe {
+ DEBUG_LEVEL_ENABLED = true;
+ }
+ debug!("debug is enabled");
+}
+
+macro_rules! call_debug {
+ ($($arg:tt)+) => (
+ fn call_print(s: &str) {
+ print!("{}", s);
+ }
+
+ call_print("called from call_debug: ");
+ debug!($($arg)+);
+ );
+}
+
+fn test2() {
+ call_debug!("debug is enabled");
+}
+
+fn main() {
+ test1();
+ test2();
+ test3();
+}
diff --git a/tests/coverage/issue-85461.cov-map b/tests/coverage/issue-85461.cov-map
new file mode 100644
index 000000000..d1c449b9a
--- /dev/null
+++ b/tests/coverage/issue-85461.cov-map
@@ -0,0 +1,8 @@
+Function name: issue_85461::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2)
+
diff --git a/tests/coverage/issue-85461.coverage b/tests/coverage/issue-85461.coverage
new file mode 100644
index 000000000..cbc910664
--- /dev/null
+++ b/tests/coverage/issue-85461.coverage
@@ -0,0 +1,37 @@
+$DIR/auxiliary/inline_always_with_dead_code.rs:
+ LL| |// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0
+ LL| |
+ LL| |#![allow(dead_code)]
+ LL| |
+ LL| |mod foo {
+ LL| | #[inline(always)]
+ LL| 2| pub fn called() {}
+ LL| |
+ LL| 0| fn uncalled() {}
+ LL| |}
+ LL| |
+ LL| |pub mod bar {
+ LL| 1| pub fn call_me() {
+ LL| 1| super::foo::called();
+ LL| 1| }
+ LL| |}
+ LL| |
+ LL| |pub mod baz {
+ LL| 1| pub fn call_me() {
+ LL| 1| super::foo::called();
+ LL| 1| }
+ LL| |}
+
+$DIR/issue-85461.rs:
+ LL| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)]
+ LL| |
+ LL| |// aux-build:inline_always_with_dead_code.rs
+ LL| |extern crate inline_always_with_dead_code;
+ LL| |
+ LL| |use inline_always_with_dead_code::{bar, baz};
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| bar::call_me();
+ LL| 1| baz::call_me();
+ LL| 1|}
+
diff --git a/tests/coverage/issue-85461.rs b/tests/coverage/issue-85461.rs
new file mode 100644
index 000000000..9d4c90a82
--- /dev/null
+++ b/tests/coverage/issue-85461.rs
@@ -0,0 +1,11 @@
+// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)]
+
+// aux-build:inline_always_with_dead_code.rs
+extern crate inline_always_with_dead_code;
+
+use inline_always_with_dead_code::{bar, baz};
+
+fn main() {
+ bar::call_me();
+ baz::call_me();
+}
diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/issue-93054.cov-map
new file mode 100644
index 000000000..c2c6e9a65
--- /dev/null
+++ b/tests/coverage/issue-93054.cov-map
@@ -0,0 +1,24 @@
+Function name: issue_93054::foo2 (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 00, 1d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 22, 1) to (start + 0, 29)
+
+Function name: issue_93054::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 00, 0d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 13)
+
+Function name: issue_93054::make (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 26, 1) to (start + 2, 2)
+
diff --git a/tests/coverage/issue-93054.coverage b/tests/coverage/issue-93054.coverage
new file mode 100644
index 000000000..15f225326
--- /dev/null
+++ b/tests/coverage/issue-93054.coverage
@@ -0,0 +1,31 @@
+ LL| |#![allow(dead_code, unreachable_code)]
+ LL| |
+ LL| |// Regression test for #93054: Functions using uninhabited types often only have a single,
+ LL| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
+ LL| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
+ LL| |
+ LL| |// compile-flags: --edition=2021
+ LL| |
+ LL| |enum Never {}
+ LL| |
+ LL| |impl Never {
+ LL| | fn foo(self) {
+ LL| | match self {}
+ LL| | make().map(|never| match never {});
+ LL| | }
+ LL| |
+ LL| | fn bar(&self) {
+ LL| | match *self {}
+ LL| | }
+ LL| |}
+ LL| |
+ LL| 0|async fn foo2(never: Never) {
+ LL| | match never {}
+ LL| |}
+ LL| |
+ LL| 0|fn make() -> Option<Never> {
+ LL| 0| None
+ LL| 0|}
+ LL| |
+ LL| 1|fn main() {}
+
diff --git a/tests/coverage/issue-93054.rs b/tests/coverage/issue-93054.rs
new file mode 100644
index 000000000..da546cfee
--- /dev/null
+++ b/tests/coverage/issue-93054.rs
@@ -0,0 +1,30 @@
+#![allow(dead_code, unreachable_code)]
+
+// Regression test for #93054: Functions using uninhabited types often only have a single,
+// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
+// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
+
+// compile-flags: --edition=2021
+
+enum Never {}
+
+impl Never {
+ fn foo(self) {
+ match self {}
+ make().map(|never| match never {});
+ }
+
+ fn bar(&self) {
+ match *self {}
+ }
+}
+
+async fn foo2(never: Never) {
+ match never {}
+}
+
+fn make() -> Option<Never> {
+ None
+}
+
+fn main() {}
diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map
new file mode 100644
index 000000000..0ad393c40
--- /dev/null
+++ b/tests/coverage/lazy_boolean.cov-map
@@ -0,0 +1,219 @@
+Function name: lazy_boolean::main
+Raw bytes (636): 0x[01, 01, a4, 01, 01, 05, 09, 8a, 05, 8f, 05, 09, 05, 02, 05, 02, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 09, 8a, 05, 8f, 05, 09, 05, 02, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 25, d2, 04, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1c, 01, 03, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 87, 05, 02, 09, 00, 11, 8f, 05, 02, 0d, 00, 12, 8a, 05, 02, 0d, 00, 12, ff, 04, 03, 09, 00, 11, 87, 05, 02, 0d, 00, 12, 82, 05, 02, 0d, 00, 12, f7, 04, 02, 09, 00, 11, ff, 04, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ef, 04, 01, 09, 00, 11, f7, 04, 00, 14, 00, 19, 15, 00, 1d, 00, 22, ef, 04, 04, 09, 00, 10, ea, 04, 01, 05, 03, 06, 19, 03, 06, 00, 07, e7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, e2, 04, 05, 05, 03, 06, df, 04, 05, 09, 00, 10, da, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, d7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, d2, 04, 02, 0c, 02, 06, cf, 04, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 164
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 2 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 5 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 7 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 8 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 9 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 10 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 11 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 12 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 13 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 14 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 15 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 16 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 17 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 18 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 19 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 20 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 21 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 22 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 23 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 24 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 25 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 26 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 27 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 28 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 29 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 30 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 31 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 32 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 33 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 34 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 35 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 36 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 37 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 38 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 39 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 40 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 41 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 42 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 43 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 44 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 45 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 46 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 47 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 48 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 49 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 50 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 51 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 52 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 53 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 54 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 55 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 56 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 57 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 58 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 59 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 60 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 61 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 62 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 63 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 64 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 65 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 66 operands: lhs = Counter(6), rhs = Expression(154, Sub)
+- expression 67 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 68 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 69 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 70 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 71 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 72 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 73 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 74 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 75 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 76 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 77 operands: lhs = Expression(153, Add), rhs = Counter(7)
+- expression 78 operands: lhs = Counter(6), rhs = Expression(154, Sub)
+- expression 79 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 80 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 81 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 82 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 83 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 84 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 85 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 86 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 87 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 88 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 89 operands: lhs = Counter(7), rhs = Expression(152, Sub)
+- expression 90 operands: lhs = Expression(153, Add), rhs = Counter(7)
+- expression 91 operands: lhs = Counter(6), rhs = Expression(154, Sub)
+- expression 92 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 93 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 94 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 95 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 96 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 97 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 98 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 99 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 100 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 101 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 102 operands: lhs = Expression(151, Add), rhs = Counter(8)
+- expression 103 operands: lhs = Counter(7), rhs = Expression(152, Sub)
+- expression 104 operands: lhs = Expression(153, Add), rhs = Counter(7)
+- expression 105 operands: lhs = Counter(6), rhs = Expression(154, Sub)
+- expression 106 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 107 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 108 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 109 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 110 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 111 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 112 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 113 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 114 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 115 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 116 operands: lhs = Counter(8), rhs = Expression(150, Sub)
+- expression 117 operands: lhs = Expression(151, Add), rhs = Counter(8)
+- expression 118 operands: lhs = Counter(7), rhs = Expression(152, Sub)
+- expression 119 operands: lhs = Expression(153, Add), rhs = Counter(7)
+- expression 120 operands: lhs = Counter(6), rhs = Expression(154, Sub)
+- expression 121 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 122 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 123 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 124 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 125 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 126 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 127 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 128 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 129 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 130 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 131 operands: lhs = Expression(149, Add), rhs = Counter(9)
+- expression 132 operands: lhs = Counter(8), rhs = Expression(150, Sub)
+- expression 133 operands: lhs = Expression(151, Add), rhs = Counter(8)
+- expression 134 operands: lhs = Counter(7), rhs = Expression(152, Sub)
+- expression 135 operands: lhs = Expression(153, Add), rhs = Counter(7)
+- expression 136 operands: lhs = Counter(6), rhs = Expression(154, Sub)
+- expression 137 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 138 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 139 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 140 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 141 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 142 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 143 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 144 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 145 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 146 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 147 operands: lhs = Counter(9), rhs = Expression(148, Sub)
+- expression 148 operands: lhs = Expression(149, Add), rhs = Counter(9)
+- expression 149 operands: lhs = Counter(8), rhs = Expression(150, Sub)
+- expression 150 operands: lhs = Expression(151, Add), rhs = Counter(8)
+- expression 151 operands: lhs = Counter(7), rhs = Expression(152, Sub)
+- expression 152 operands: lhs = Expression(153, Add), rhs = Counter(7)
+- expression 153 operands: lhs = Counter(6), rhs = Expression(154, Sub)
+- expression 154 operands: lhs = Expression(155, Add), rhs = Counter(6)
+- expression 155 operands: lhs = Counter(5), rhs = Expression(156, Sub)
+- expression 156 operands: lhs = Expression(157, Add), rhs = Counter(5)
+- expression 157 operands: lhs = Counter(4), rhs = Expression(158, Sub)
+- expression 158 operands: lhs = Expression(159, Add), rhs = Counter(4)
+- expression 159 operands: lhs = Counter(3), rhs = Expression(160, Sub)
+- expression 160 operands: lhs = Expression(161, Add), rhs = Counter(3)
+- expression 161 operands: lhs = Counter(2), rhs = Expression(162, Sub)
+- expression 162 operands: lhs = Expression(163, Add), rhs = Counter(2)
+- expression 163 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 28
+- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15)
+- Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6)
+- Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(161, Add)) at (prev + 2, 9) to (start + 0, 17)
+ = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(163, Add)) at (prev + 2, 13) to (start + 0, 18)
+ = (c1 + (c0 - c1))
+- Code(Expression(162, Sub)) at (prev + 2, 13) to (start + 0, 18)
+ = ((c1 + (c0 - c1)) - c2)
+- Code(Expression(159, Add)) at (prev + 3, 9) to (start + 0, 17)
+ = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Expression(161, Add)) at (prev + 2, 13) to (start + 0, 18)
+ = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(160, Sub)) at (prev + 2, 13) to (start + 0, 18)
+ = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
+- Code(Expression(157, Add)) at (prev + 2, 9) to (start + 0, 17)
+ = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Expression(159, Add)) at (prev + 0, 20) to (start + 0, 25)
+ = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(4)) at (prev + 0, 29) to (start + 0, 34)
+- Code(Expression(155, Add)) at (prev + 1, 9) to (start + 0, 17)
+ = (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5))
+- Code(Expression(157, Add)) at (prev + 0, 20) to (start + 0, 25)
+ = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Counter(5)) at (prev + 0, 29) to (start + 0, 34)
+- Code(Expression(155, Add)) at (prev + 4, 9) to (start + 0, 16)
+ = (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5))
+- Code(Expression(154, Sub)) at (prev + 1, 5) to (start + 3, 6)
+ = ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)
+- Code(Counter(6)) at (prev + 3, 6) to (start + 0, 7)
+- Code(Expression(153, Add)) at (prev + 3, 9) to (start + 0, 16)
+ = (c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6))
+- Code(Counter(7)) at (prev + 1, 5) to (start + 3, 6)
+- Code(Expression(152, Sub)) at (prev + 5, 5) to (start + 3, 6)
+ = ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)
+- Code(Expression(151, Add)) at (prev + 5, 9) to (start + 0, 16)
+ = (c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7))
+- Code(Expression(150, Sub)) at (prev + 0, 17) to (start + 2, 6)
+ = ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)
+- Code(Counter(8)) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(149, Add)) at (prev + 2, 8) to (start + 0, 15)
+ = (c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8))
+- Code(Counter(9)) at (prev + 0, 16) to (start + 2, 6)
+- Code(Expression(148, Sub)) at (prev + 2, 12) to (start + 2, 6)
+ = ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9)
+- Code(Expression(147, Add)) at (prev + 3, 1) to (start + 0, 2)
+ = (c9 + ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9))
+
diff --git a/tests/coverage/lazy_boolean.coverage b/tests/coverage/lazy_boolean.coverage
new file mode 100644
index 000000000..8f14082ef
--- /dev/null
+++ b/tests/coverage/lazy_boolean.coverage
@@ -0,0 +1,64 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let (mut a, mut b, mut c) = (0, 0, 0);
+ LL| 1| if is_true {
+ LL| 1| a = 1;
+ LL| 1| b = 10;
+ LL| 1| c = 100;
+ LL| 1| }
+ ^0
+ LL| | let
+ LL| 1| somebool
+ LL| | =
+ LL| 1| a < b
+ LL| | ||
+ LL| 0| b < c
+ LL| | ;
+ LL| | let
+ LL| 1| somebool
+ LL| | =
+ LL| 1| b < a
+ LL| | ||
+ LL| 1| b < c
+ LL| | ;
+ LL| 1| let somebool = a < b && b < c;
+ LL| 1| let somebool = b < a && b < c;
+ ^0
+ LL| |
+ LL| | if
+ LL| | !
+ LL| 1| is_true
+ LL| 0| {
+ LL| 0| a = 2
+ LL| 0| ;
+ LL| 1| }
+ LL| |
+ LL| | if
+ LL| 1| is_true
+ LL| 1| {
+ LL| 1| b = 30
+ LL| 1| ;
+ LL| 1| }
+ LL| | else
+ LL| 0| {
+ LL| 0| c = 400
+ LL| 0| ;
+ LL| 0| }
+ LL| |
+ LL| 1| if !is_true {
+ LL| 0| a = 2;
+ LL| 1| }
+ LL| |
+ LL| 1| if is_true {
+ LL| 1| b = 30;
+ LL| 1| } else {
+ LL| 0| c = 400;
+ LL| 0| }
+ LL| 1|}
+
diff --git a/tests/coverage/lazy_boolean.rs b/tests/coverage/lazy_boolean.rs
new file mode 100644
index 000000000..bb6219e85
--- /dev/null
+++ b/tests/coverage/lazy_boolean.rs
@@ -0,0 +1,61 @@
+#![allow(unused_assignments, unused_variables)]
+
+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, mut b, mut c) = (0, 0, 0);
+ if is_true {
+ a = 1;
+ b = 10;
+ c = 100;
+ }
+ let
+ somebool
+ =
+ a < b
+ ||
+ b < c
+ ;
+ let
+ somebool
+ =
+ b < a
+ ||
+ b < c
+ ;
+ let somebool = a < b && b < c;
+ let somebool = b < a && b < c;
+
+ if
+ !
+ is_true
+ {
+ a = 2
+ ;
+ }
+
+ if
+ is_true
+ {
+ b = 30
+ ;
+ }
+ else
+ {
+ c = 400
+ ;
+ }
+
+ if !is_true {
+ a = 2;
+ }
+
+ if is_true {
+ b = 30;
+ } else {
+ c = 400;
+ }
+}
diff --git a/tests/coverage/long_and_wide.cov-map b/tests/coverage/long_and_wide.cov-map
new file mode 100644
index 000000000..97aebf9b1
--- /dev/null
+++ b/tests/coverage/long_and_wide.cov-map
@@ -0,0 +1,32 @@
+Function name: long_and_wide::far_function
+Raw bytes (10): 0x[01, 01, 00, 01, 01, 96, 01, 01, 00, 15]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 150, 1) to (start + 0, 21)
+
+Function name: long_and_wide::long_function
+Raw bytes (10): 0x[01, 01, 00, 01, 01, 10, 01, 84, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 16, 1) to (start + 132, 2)
+
+Function name: long_and_wide::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 04, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 7, 1) to (start + 4, 2)
+
+Function name: long_and_wide::wide_function
+Raw bytes (10): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 8b, 01]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 139)
+
diff --git a/tests/coverage/long_and_wide.coverage b/tests/coverage/long_and_wide.coverage
new file mode 100644
index 000000000..d7d29ca40
--- /dev/null
+++ b/tests/coverage/long_and_wide.coverage
@@ -0,0 +1,151 @@
+ LL| |// compile-flags: --edition=2021
+ LL| |// ignore-tidy-linelength
+ LL| |
+ LL| |// This file deliberately contains line and column numbers larger than 127,
+ LL| |// to verify that `coverage-dump`'s ULEB128 parser can handle them.
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| wide_function();
+ LL| 1| long_function();
+ LL| 1| far_function();
+ LL| 1|}
+ LL| |
+ LL| |#[rustfmt::skip]
+ LL| 1|fn wide_function() { /* */ (); }
+ LL| |
+ LL| 1|fn long_function() {
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1| //
+ LL| 1|}
+ LL| |
+ LL| 1|fn far_function() {}
+
diff --git a/tests/coverage/long_and_wide.rs b/tests/coverage/long_and_wide.rs
new file mode 100644
index 000000000..a7cbcd480
--- /dev/null
+++ b/tests/coverage/long_and_wide.rs
@@ -0,0 +1,150 @@
+// compile-flags: --edition=2021
+// ignore-tidy-linelength
+
+// This file deliberately contains line and column numbers larger than 127,
+// to verify that `coverage-dump`'s ULEB128 parser can handle them.
+
+fn main() {
+ wide_function();
+ long_function();
+ far_function();
+}
+
+#[rustfmt::skip]
+fn wide_function() { /* */ (); }
+
+fn long_function() {
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+}
+
+fn far_function() {}
diff --git a/tests/coverage/loop_break_value.cov-map b/tests/coverage/loop_break_value.cov-map
new file mode 100644
index 000000000..75018442d
--- /dev/null
+++ b/tests/coverage/loop_break_value.cov-map
@@ -0,0 +1,8 @@
+Function name: loop_break_value::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 0a, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 3, 1) to (start + 10, 2)
+
diff --git a/tests/coverage/loop_break_value.coverage b/tests/coverage/loop_break_value.coverage
new file mode 100644
index 000000000..1f0630636
--- /dev/null
+++ b/tests/coverage/loop_break_value.coverage
@@ -0,0 +1,14 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let result
+ LL| 1| =
+ LL| 1| loop
+ LL| 1| {
+ LL| 1| break
+ LL| 1| 10
+ LL| 1| ;
+ LL| 1| }
+ LL| 1| ;
+ LL| 1|}
+
diff --git a/tests/coverage/loop_break_value.rs b/tests/coverage/loop_break_value.rs
new file mode 100644
index 000000000..dbc4fad7a
--- /dev/null
+++ b/tests/coverage/loop_break_value.rs
@@ -0,0 +1,13 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+ let result
+ =
+ loop
+ {
+ break
+ 10
+ ;
+ }
+ ;
+}
diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map
new file mode 100644
index 000000000..813583a9d
--- /dev/null
+++ b/tests/coverage/loops_branches.cov-map
@@ -0,0 +1,183 @@
+Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt
+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 = 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 = 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 = 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 = 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 = 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 = Zero
+- expression 24 operands: lhs = Zero, rhs = Expression(43, Sub)
+- 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 = 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 = 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 = 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 = 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 = 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 - Zero)
+- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30)
+ = (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 + Zero)) - c6)
+- Code(Expression(46, Add)) at (prev + 0, 18) to (start + 0, 23)
+ = ((c3 + Zero) + (c4 + Zero))
+- Code(Expression(45, Sub)) at (prev + 1, 16) to (start + 0, 20)
+ = (((c3 + Zero) + (c4 + Zero)) - c6)
+- Code(Expression(44, Sub)) at (prev + 1, 20) to (start + 0, 25)
+ = ((((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 + Zero)) - c6) - Zero) - Zero)
+- Code(Expression(42, Add)) at (prev + 1, 17) to (start + 0, 34)
+ = (Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero))
+- Code(Expression(41, Sub)) at (prev + 0, 34) to (start + 0, 35)
+ = ((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 + Zero)) - c6) - Zero) - Zero)) - c4) + c6))
+
+Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt
+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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 - 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 - Zero) - Zero)
+- Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30)
+ = (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)
+ = (((Zero + c3) + (Zero + c5)) - c6)
+- Code(Expression(47, Add)) at (prev + 0, 18) to (start + 0, 23)
+ = ((Zero + c3) + (Zero + c5))
+- Code(Expression(46, Sub)) at (prev + 1, 16) to (start + 0, 21)
+ = (((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)
+ = ((((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)
+ = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)
+- Code(Expression(43, Add)) at (prev + 1, 17) to (start + 0, 34)
+ = (Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero))
+- Code(Expression(42, Sub)) at (prev + 0, 34) to (start + 0, 35)
+ = ((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 + (((((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]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 55, 1) to (start + 5, 2)
+
diff --git a/tests/coverage/loops_branches.coverage b/tests/coverage/loops_branches.coverage
new file mode 100644
index 000000000..8cd6f1be3
--- /dev/null
+++ b/tests/coverage/loops_branches.coverage
@@ -0,0 +1,67 @@
+ LL| |#![allow(unused_assignments, unused_variables, while_true)]
+ LL| |
+ LL| |// This test confirms that (1) unexecuted infinite loops are handled correctly by the
+ LL| |// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped.
+ LL| |
+ LL| |struct DebugTest;
+ LL| |
+ LL| |impl std::fmt::Debug for DebugTest {
+ LL| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ LL| 1| if true {
+ LL| 1| if false {
+ LL| 0| while true {}
+ LL| 1| }
+ LL| 1| write!(f, "cool")?;
+ ^0
+ LL| 0| } else {
+ LL| 0| }
+ LL| |
+ LL| 11| for i in 0..10 {
+ ^10
+ LL| 10| if true {
+ LL| 10| if false {
+ LL| 0| while true {}
+ LL| 10| }
+ LL| 10| write!(f, "cool")?;
+ ^0
+ LL| 0| } else {
+ LL| 0| }
+ LL| | }
+ LL| 1| Ok(())
+ LL| 1| }
+ LL| |}
+ LL| |
+ LL| |struct DisplayTest;
+ LL| |
+ LL| |impl std::fmt::Display for DisplayTest {
+ LL| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ LL| 1| if false {
+ LL| 0| } else {
+ LL| 1| if false {
+ LL| 0| while true {}
+ LL| 1| }
+ LL| 1| write!(f, "cool")?;
+ ^0
+ LL| | }
+ LL| 11| for i in 0..10 {
+ ^10
+ LL| 10| if false {
+ LL| 0| } else {
+ LL| 10| if false {
+ LL| 0| while true {}
+ LL| 10| }
+ LL| 10| write!(f, "cool")?;
+ ^0
+ LL| | }
+ LL| | }
+ LL| 1| Ok(())
+ LL| 1| }
+ LL| |}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let debug_test = DebugTest;
+ LL| 1| println!("{:?}", debug_test);
+ LL| 1| let display_test = DisplayTest;
+ LL| 1| println!("{}", display_test);
+ LL| 1|}
+
diff --git a/tests/coverage/loops_branches.rs b/tests/coverage/loops_branches.rs
new file mode 100644
index 000000000..f3a343bcc
--- /dev/null
+++ b/tests/coverage/loops_branches.rs
@@ -0,0 +1,60 @@
+#![allow(unused_assignments, unused_variables, while_true)]
+
+// This test confirms that (1) unexecuted infinite loops are handled correctly by the
+// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped.
+
+struct DebugTest;
+
+impl std::fmt::Debug for DebugTest {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ if true {
+ if false {
+ while true {}
+ }
+ write!(f, "cool")?;
+ } else {
+ }
+
+ for i in 0..10 {
+ if true {
+ if false {
+ while true {}
+ }
+ write!(f, "cool")?;
+ } else {
+ }
+ }
+ Ok(())
+ }
+}
+
+struct DisplayTest;
+
+impl std::fmt::Display for DisplayTest {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ if false {
+ } else {
+ if false {
+ while true {}
+ }
+ write!(f, "cool")?;
+ }
+ for i in 0..10 {
+ if false {
+ } else {
+ if false {
+ while true {}
+ }
+ write!(f, "cool")?;
+ }
+ }
+ Ok(())
+ }
+}
+
+fn main() {
+ let debug_test = DebugTest;
+ println!("{:?}", debug_test);
+ let display_test = DisplayTest;
+ println!("{}", display_test);
+}
diff --git a/tests/coverage/macro_name_span.cov-map b/tests/coverage/macro_name_span.cov-map
new file mode 100644
index 000000000..b84628fc7
--- /dev/null
+++ b/tests/coverage/macro_name_span.cov-map
@@ -0,0 +1,16 @@
+Function name: macro_name_span::affected_function
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 1b, 00, 20]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 6, 27) to (start + 0, 32)
+
+Function name: macro_name_span::main
+Raw bytes (9): 0x[01, 02, 00, 01, 01, 0b, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 2
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2)
+
diff --git a/tests/coverage/macro_name_span.coverage b/tests/coverage/macro_name_span.coverage
new file mode 100644
index 000000000..cadf70246
--- /dev/null
+++ b/tests/coverage/macro_name_span.coverage
@@ -0,0 +1,39 @@
+$DIR/auxiliary/macro_name_span_helper.rs:
+ LL| |// edition: 2021
+ LL| |
+ LL| |#[macro_export]
+ LL| |macro_rules! macro_that_defines_a_function {
+ LL| | (fn $name:ident () $body:tt) => {
+ LL| 1| fn $name () -> () $body
+ LL| | }
+ LL| |}
+ LL| |
+ LL| |// Non-executable comment.
+
+$DIR/macro_name_span.rs:
+ LL| |// edition: 2021
+ LL| |
+ LL| |// Regression test for <https://github.com/rust-lang/rust/issues/117788>.
+ LL| |// Under some circumstances, the heuristics that detect macro name spans can
+ LL| |// get confused and produce incorrect spans beyond the bounds of the span
+ LL| |// being processed.
+ LL| |
+ LL| |// aux-build: macro_name_span_helper.rs
+ LL| |extern crate macro_name_span_helper;
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| affected_function();
+ LL| 1|}
+ LL| |
+ LL| |macro_rules! macro_with_an_unreasonably_and_egregiously_long_name {
+ LL| | () => {
+ LL| | println!("hello");
+ LL| | };
+ LL| |}
+ LL| |
+ LL| |macro_name_span_helper::macro_that_defines_a_function! {
+ LL| | fn affected_function() {
+ LL| | macro_with_an_unreasonably_and_egregiously_long_name!();
+ LL| | }
+ LL| |}
+
diff --git a/tests/coverage/macro_name_span.rs b/tests/coverage/macro_name_span.rs
new file mode 100644
index 000000000..5d15977c4
--- /dev/null
+++ b/tests/coverage/macro_name_span.rs
@@ -0,0 +1,25 @@
+// edition: 2021
+
+// Regression test for <https://github.com/rust-lang/rust/issues/117788>.
+// Under some circumstances, the heuristics that detect macro name spans can
+// get confused and produce incorrect spans beyond the bounds of the span
+// being processed.
+
+// aux-build: macro_name_span_helper.rs
+extern crate macro_name_span_helper;
+
+fn main() {
+ affected_function();
+}
+
+macro_rules! macro_with_an_unreasonably_and_egregiously_long_name {
+ () => {
+ println!("hello");
+ };
+}
+
+macro_name_span_helper::macro_that_defines_a_function! {
+ fn affected_function() {
+ macro_with_an_unreasonably_and_egregiously_long_name!();
+ }
+}
diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map
new file mode 100644
index 000000000..d63407a99
--- /dev/null
+++ b/tests/coverage/match_or_pattern.cov-map
@@ -0,0 +1,83 @@
+Function name: match_or_pattern::main
+Raw bytes (202): 0x[01, 01, 23, 01, 05, 05, 02, 09, 0d, 2f, 11, 09, 0d, 2b, 15, 2f, 11, 09, 0d, 15, 26, 2b, 15, 2f, 11, 09, 0d, 19, 1d, 57, 21, 19, 1d, 53, 25, 57, 21, 19, 1d, 25, 4e, 53, 25, 57, 21, 19, 1d, 29, 2d, 7f, 31, 29, 2d, 7b, 35, 7f, 31, 29, 2d, 35, 76, 7b, 35, 7f, 31, 29, 2d, 39, 3d, 8b, 01, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 07, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 2f, 01, 0e, 00, 10, 2b, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 26, 03, 06, 00, 07, 23, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 57, 01, 0e, 00, 10, 53, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 4e, 03, 06, 00, 07, 4b, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 7f, 01, 0e, 00, 10, 7b, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 76, 03, 06, 00, 07, 73, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 8b, 01, 01, 0e, 00, 10, 87, 01, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 35
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 5 operands: lhs = Expression(10, Add), rhs = Counter(5)
+- expression 6 operands: lhs = Expression(11, Add), rhs = Counter(4)
+- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 8 operands: lhs = Counter(5), rhs = Expression(9, Sub)
+- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(5)
+- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4)
+- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 13 operands: lhs = Expression(21, Add), rhs = Counter(8)
+- expression 14 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 15 operands: lhs = Expression(20, Add), rhs = Counter(9)
+- expression 16 operands: lhs = Expression(21, Add), rhs = Counter(8)
+- expression 17 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 18 operands: lhs = Counter(9), rhs = Expression(19, Sub)
+- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(9)
+- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(8)
+- expression 21 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 22 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 23 operands: lhs = Expression(31, Add), rhs = Counter(12)
+- expression 24 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 25 operands: lhs = Expression(30, Add), rhs = Counter(13)
+- expression 26 operands: lhs = Expression(31, Add), rhs = Counter(12)
+- expression 27 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 28 operands: lhs = Counter(13), rhs = Expression(29, Sub)
+- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(13)
+- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(12)
+- expression 31 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 32 operands: lhs = Counter(14), rhs = Counter(15)
+- expression 33 operands: lhs = Expression(34, Add), rhs = Counter(16)
+- expression 34 operands: lhs = Counter(14), rhs = Counter(15)
+Number of file 0 mappings: 25
+- Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15)
+- Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6)
+- Code(Expression(0, Sub)) at (prev + 3, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 11) to (start + 0, 17)
+ = (c1 + (c0 - c1))
+- Code(Counter(4)) at (prev + 3, 27) to (start + 0, 29)
+- Code(Expression(11, Add)) at (prev + 1, 14) to (start + 0, 16)
+ = (c2 + c3)
+- Code(Expression(10, Add)) at (prev + 2, 8) to (start + 0, 15)
+ = ((c2 + c3) + c4)
+- Code(Counter(5)) at (prev + 0, 16) to (start + 3, 6)
+- Code(Expression(9, Sub)) at (prev + 3, 6) to (start + 0, 7)
+ = (((c2 + c3) + c4) - c5)
+- Code(Expression(8, Add)) at (prev + 1, 11) to (start + 0, 17)
+ = (c5 + (((c2 + c3) + c4) - c5))
+- Code(Counter(8)) at (prev + 1, 27) to (start + 0, 29)
+- Code(Expression(21, Add)) at (prev + 1, 14) to (start + 0, 16)
+ = (c6 + c7)
+- Code(Expression(20, Add)) at (prev + 2, 8) to (start + 0, 15)
+ = ((c6 + c7) + c8)
+- Code(Counter(9)) at (prev + 0, 16) to (start + 3, 6)
+- Code(Expression(19, Sub)) at (prev + 3, 6) to (start + 0, 7)
+ = (((c6 + c7) + c8) - c9)
+- Code(Expression(18, Add)) at (prev + 1, 11) to (start + 0, 17)
+ = (c9 + (((c6 + c7) + c8) - c9))
+- Code(Counter(12)) at (prev + 1, 27) to (start + 0, 29)
+- Code(Expression(31, Add)) at (prev + 1, 14) to (start + 0, 16)
+ = (c10 + c11)
+- Code(Expression(30, Add)) at (prev + 2, 8) to (start + 0, 15)
+ = ((c10 + c11) + c12)
+- Code(Counter(13)) at (prev + 0, 16) to (start + 3, 6)
+- Code(Expression(29, Sub)) at (prev + 3, 6) to (start + 0, 7)
+ = (((c10 + c11) + c12) - c13)
+- Code(Expression(28, Add)) at (prev + 1, 11) to (start + 0, 17)
+ = (c13 + (((c10 + c11) + c12) - c13))
+- Code(Counter(16)) at (prev + 1, 27) to (start + 0, 29)
+- Code(Expression(34, Add)) at (prev + 1, 14) to (start + 0, 16)
+ = (c14 + c15)
+- Code(Expression(33, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = ((c14 + c15) + c16)
+
diff --git a/tests/coverage/match_or_pattern.coverage b/tests/coverage/match_or_pattern.coverage
new file mode 100644
index 000000000..94c796721
--- /dev/null
+++ b/tests/coverage/match_or_pattern.coverage
@@ -0,0 +1,48 @@
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let mut a: u8 = 0;
+ LL| 1| let mut b: u8 = 0;
+ LL| 1| if is_true {
+ LL| 1| a = 2;
+ LL| 1| b = 0;
+ LL| 1| }
+ ^0
+ LL| 1| match (a, b) {
+ LL| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`.
+ LL| | // This test confirms a fix for Issue #79569.
+ LL| 0| (0 | 1, 2 | 3) => {}
+ LL| 1| _ => {}
+ LL| | }
+ LL| 1| if is_true {
+ LL| 1| a = 0;
+ LL| 1| b = 0;
+ LL| 1| }
+ ^0
+ LL| 1| match (a, b) {
+ LL| 0| (0 | 1, 2 | 3) => {}
+ LL| 1| _ => {}
+ LL| | }
+ LL| 1| if is_true {
+ LL| 1| a = 2;
+ LL| 1| b = 2;
+ LL| 1| }
+ ^0
+ LL| 1| match (a, b) {
+ LL| 0| (0 | 1, 2 | 3) => {}
+ LL| 1| _ => {}
+ LL| | }
+ LL| 1| if is_true {
+ LL| 1| a = 0;
+ LL| 1| b = 2;
+ LL| 1| }
+ ^0
+ LL| 1| match (a, b) {
+ LL| 1| (0 | 1, 2 | 3) => {}
+ LL| 0| _ => {}
+ LL| | }
+ LL| 1|}
+
diff --git a/tests/coverage/match_or_pattern.rs b/tests/coverage/match_or_pattern.rs
new file mode 100644
index 000000000..ab7aee51d
--- /dev/null
+++ b/tests/coverage/match_or_pattern.rs
@@ -0,0 +1,43 @@
+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/tests/coverage/nested_loops.cov-map b/tests/coverage/nested_loops.cov-map
new file mode 100644
index 000000000..35d92594e
--- /dev/null
+++ b/tests/coverage/nested_loops.cov-map
@@ -0,0 +1,51 @@
+Function name: nested_loops::main
+Raw bytes (115): 0x[01, 01, 17, 01, 57, 05, 09, 03, 0d, 4e, 53, 03, 0d, 15, 19, 4b, 09, 4e, 53, 03, 0d, 15, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 42, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 05, 09, 11, 0d, 0d, 01, 01, 01, 02, 1b, 03, 04, 13, 00, 20, 4e, 01, 0d, 01, 18, 4b, 02, 12, 00, 17, 46, 01, 10, 00, 16, 05, 01, 11, 00, 16, 42, 01, 0e, 03, 16, 3e, 04, 11, 01, 1b, 11, 02, 15, 00, 21, 15, 01, 18, 02, 12, 19, 03, 0e, 00, 0f, 57, 02, 09, 00, 17, 5b, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 23
+- expression 0 operands: lhs = Counter(0), rhs = Expression(21, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add)
+- expression 4 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 6 operands: lhs = Expression(18, Add), rhs = Counter(2)
+- expression 7 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add)
+- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 9 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 10 operands: lhs = Expression(17, Sub), rhs = Counter(1)
+- expression 11 operands: lhs = Expression(18, Add), rhs = Counter(2)
+- expression 12 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add)
+- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 14 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(6)
+- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(1)
+- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(2)
+- expression 18 operands: lhs = Expression(19, Sub), rhs = Expression(20, Add)
+- expression 19 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 20 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 21 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 22 operands: lhs = Counter(4), rhs = Counter(3)
+Number of file 0 mappings: 13
+- Code(Counter(0)) at (prev + 1, 1) to (start + 2, 27)
+- Code(Expression(0, Add)) at (prev + 4, 19) to (start + 0, 32)
+ = (c0 + (c1 + c2))
+- Code(Expression(19, Sub)) at (prev + 1, 13) to (start + 1, 24)
+ = ((c0 + (c1 + c2)) - c3)
+- Code(Expression(18, Add)) at (prev + 2, 18) to (start + 0, 23)
+ = (((c0 + (c1 + c2)) - c3) + (c5 + c6))
+- Code(Expression(17, Sub)) at (prev + 1, 16) to (start + 0, 22)
+ = ((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2)
+- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 22)
+- Code(Expression(16, Sub)) at (prev + 1, 14) to (start + 3, 22)
+ = (((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2) - c1)
+- Code(Expression(15, Sub)) at (prev + 4, 17) to (start + 1, 27)
+ = ((((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2) - c1) - c6)
+- Code(Counter(4)) at (prev + 2, 21) to (start + 0, 33)
+- Code(Counter(5)) at (prev + 1, 24) to (start + 2, 18)
+- Code(Counter(6)) at (prev + 3, 14) to (start + 0, 15)
+- Code(Expression(21, Add)) at (prev + 2, 9) to (start + 0, 23)
+ = (c1 + c2)
+- Code(Expression(22, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = (c4 + c3)
+
diff --git a/tests/coverage/nested_loops.coverage b/tests/coverage/nested_loops.coverage
new file mode 100644
index 000000000..143d0d26a
--- /dev/null
+++ b/tests/coverage/nested_loops.coverage
@@ -0,0 +1,26 @@
+ LL| 1|fn main() {
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1| let mut countdown = 10;
+ LL| |
+ LL| 1| 'outer: while countdown > 0 {
+ LL| 1| let mut a = 100;
+ LL| 1| let mut b = 100;
+ LL| 3| for _ in 0..50 {
+ LL| 3| if a < 30 {
+ LL| 0| break;
+ LL| 3| }
+ LL| 3| a -= 5;
+ LL| 3| b -= 5;
+ LL| 3| if b < 90 {
+ LL| 1| a -= 10;
+ LL| 1| if is_true {
+ LL| 1| break 'outer;
+ LL| 0| } else {
+ LL| 0| a -= 2;
+ LL| 0| }
+ LL| 2| }
+ LL| | }
+ LL| 0| countdown -= 1;
+ LL| | }
+ LL| 1|}
+
diff --git a/tests/coverage/nested_loops.rs b/tests/coverage/nested_loops.rs
new file mode 100644
index 000000000..4c7c78427
--- /dev/null
+++ b/tests/coverage/nested_loops.rs
@@ -0,0 +1,25 @@
+fn main() {
+ let is_true = std::env::args().len() == 1;
+ let mut countdown = 10;
+
+ 'outer: while countdown > 0 {
+ let mut a = 100;
+ let mut b = 100;
+ for _ in 0..50 {
+ if a < 30 {
+ break;
+ }
+ a -= 5;
+ b -= 5;
+ if b < 90 {
+ a -= 10;
+ if is_true {
+ break 'outer;
+ } else {
+ a -= 2;
+ }
+ }
+ }
+ countdown -= 1;
+ }
+}
diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map
new file mode 100644
index 000000000..05b6448bb
--- /dev/null
+++ b/tests/coverage/no_cov_crate.cov-map
@@ -0,0 +1,78 @@
+Function name: no_cov_crate::add_coverage_1
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 20, 1) to (start + 2, 2)
+
+Function name: no_cov_crate::add_coverage_2
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2)
+
+Function name: no_cov_crate::add_coverage_not_called (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 1d, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 29, 1) to (start + 2, 2)
+
+Function name: no_cov_crate::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 4d, 01, 0b, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 77, 1) to (start + 11, 2)
+
+Function name: no_cov_crate::nested_fns::outer
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 05, 0c, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 49, 5) to (start + 12, 6)
+
+Function name: no_cov_crate::nested_fns::outer_both_covered
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 3f, 05, 0b, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 63, 5) to (start + 11, 6)
+
+Function name: no_cov_crate::nested_fns::outer_both_covered::inner
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 67, 9) to (start + 1, 23)
+- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
+- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
+ = (c1 + (c0 - c1))
+
+Function name: no_cov_crate::nested_fns::outer_not_covered::inner
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 38, 9) to (start + 1, 23)
+- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
+- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
+ = (c1 + (c0 - c1))
+
diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/no_cov_crate.coverage
new file mode 100644
index 000000000..f5a0322bf
--- /dev/null
+++ b/tests/coverage/no_cov_crate.coverage
@@ -0,0 +1,89 @@
+ LL| |// Enables `coverage(off)` on the entire crate
+ LL| |#![feature(coverage_attribute)]
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |fn do_not_add_coverage_1() {
+ LL| | println!("called but not covered");
+ LL| |}
+ LL| |
+ LL| |fn do_not_add_coverage_2() {
+ LL| | #![coverage(off)]
+ LL| | println!("called but not covered");
+ LL| |}
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |#[allow(dead_code)]
+ LL| |fn do_not_add_coverage_not_called() {
+ LL| | println!("not called and not covered");
+ LL| |}
+ LL| |
+ LL| 1|fn add_coverage_1() {
+ LL| 1| println!("called and covered");
+ LL| 1|}
+ LL| |
+ LL| 1|fn add_coverage_2() {
+ LL| 1| println!("called and covered");
+ LL| 1|}
+ LL| |
+ LL| |#[allow(dead_code)]
+ LL| 0|fn add_coverage_not_called() {
+ LL| 0| println!("not called but covered");
+ LL| 0|}
+ LL| |
+ LL| |// FIXME: These test-cases illustrate confusing results of nested functions.
+ LL| |// See https://github.com/rust-lang/rust/issues/93319
+ LL| |mod nested_fns {
+ LL| | #[coverage(off)]
+ LL| | pub fn outer_not_covered(is_true: bool) {
+ LL| 1| fn inner(is_true: bool) {
+ LL| 1| if is_true {
+ LL| 1| println!("called and covered");
+ LL| 1| } else {
+ LL| 0| println!("absolutely not covered");
+ LL| 0| }
+ LL| 1| }
+ LL| | println!("called but not covered");
+ LL| | inner(is_true);
+ LL| | }
+ LL| |
+ LL| 1| pub fn outer(is_true: bool) {
+ LL| 1| println!("called and covered");
+ LL| 1| inner_not_covered(is_true);
+ LL| 1|
+ LL| 1| #[coverage(off)]
+ LL| 1| fn inner_not_covered(is_true: bool) {
+ LL| 1| if is_true {
+ LL| 1| println!("called but not covered");
+ LL| 1| } else {
+ LL| 1| println!("absolutely not covered");
+ LL| 1| }
+ LL| 1| }
+ LL| 1| }
+ LL| |
+ LL| 1| pub fn outer_both_covered(is_true: bool) {
+ LL| 1| println!("called and covered");
+ LL| 1| inner(is_true);
+ LL| 1|
+ LL| 1| fn inner(is_true: bool) {
+ LL| 1| if is_true {
+ LL| 1| println!("called and covered");
+ LL| 1| } else {
+ LL| 0| println!("absolutely not covered");
+ LL| 0| }
+ LL| 1| }
+ LL| 1| }
+ LL| |}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| do_not_add_coverage_1();
+ LL| 1| do_not_add_coverage_2();
+ LL| 1| add_coverage_1();
+ LL| 1| add_coverage_2();
+ LL| 1|
+ LL| 1| nested_fns::outer_not_covered(is_true);
+ LL| 1| nested_fns::outer(is_true);
+ LL| 1| nested_fns::outer_both_covered(is_true);
+ LL| 1|}
+
diff --git a/tests/coverage/no_cov_crate.rs b/tests/coverage/no_cov_crate.rs
new file mode 100644
index 000000000..e12e4bc55
--- /dev/null
+++ b/tests/coverage/no_cov_crate.rs
@@ -0,0 +1,88 @@
+// Enables `coverage(off)` on the entire crate
+#![feature(coverage_attribute)]
+
+#[coverage(off)]
+fn do_not_add_coverage_1() {
+ println!("called but not covered");
+}
+
+fn do_not_add_coverage_2() {
+ #![coverage(off)]
+ println!("called but not covered");
+}
+
+#[coverage(off)]
+#[allow(dead_code)]
+fn do_not_add_coverage_not_called() {
+ println!("not called and not covered");
+}
+
+fn add_coverage_1() {
+ println!("called and covered");
+}
+
+fn add_coverage_2() {
+ println!("called and covered");
+}
+
+#[allow(dead_code)]
+fn add_coverage_not_called() {
+ println!("not called but covered");
+}
+
+// FIXME: These test-cases illustrate confusing results of nested functions.
+// See https://github.com/rust-lang/rust/issues/93319
+mod nested_fns {
+ #[coverage(off)]
+ pub fn outer_not_covered(is_true: bool) {
+ fn inner(is_true: bool) {
+ if is_true {
+ println!("called and covered");
+ } else {
+ println!("absolutely not covered");
+ }
+ }
+ println!("called but not covered");
+ inner(is_true);
+ }
+
+ pub fn outer(is_true: bool) {
+ println!("called and covered");
+ inner_not_covered(is_true);
+
+ #[coverage(off)]
+ fn inner_not_covered(is_true: bool) {
+ if is_true {
+ println!("called but not covered");
+ } else {
+ println!("absolutely not covered");
+ }
+ }
+ }
+
+ pub fn outer_both_covered(is_true: bool) {
+ println!("called and covered");
+ inner(is_true);
+
+ fn inner(is_true: bool) {
+ if is_true {
+ println!("called and covered");
+ } else {
+ println!("absolutely not covered");
+ }
+ }
+ }
+}
+
+fn main() {
+ let is_true = std::env::args().len() == 1;
+
+ do_not_add_coverage_1();
+ do_not_add_coverage_2();
+ add_coverage_1();
+ add_coverage_2();
+
+ nested_fns::outer_not_covered(is_true);
+ nested_fns::outer(is_true);
+ nested_fns::outer_both_covered(is_true);
+}
diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map
new file mode 100644
index 000000000..39a5c05f8
--- /dev/null
+++ b/tests/coverage/overflow.cov-map
@@ -0,0 +1,43 @@
+Function name: overflow::main
+Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 10, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 03, 0a, 12, 03, 13, 00, 20, 09, 00, 21, 03, 0a, 0d, 03, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 8
+- expression 0 operands: lhs = Counter(0), rhs = Expression(6, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(1)
+- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(4)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 27)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24)
+ = (c0 + (c1 + (c2 + c3)))
+- Code(Expression(5, Sub)) at (prev + 1, 12) to (start + 0, 26)
+ = ((c0 + (c1 + (c2 + c3))) - c4)
+- Code(Counter(1)) at (prev + 0, 27) to (start + 3, 10)
+- Code(Expression(4, Sub)) at (prev + 3, 19) to (start + 0, 32)
+ = (((c0 + (c1 + (c2 + c3))) - c4) - c1)
+- Code(Counter(2)) at (prev + 0, 33) to (start + 3, 10)
+- Code(Counter(3)) at (prev + 3, 10) to (start + 0, 11)
+- Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23)
+ = (c1 + (c2 + c3))
+- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2)
+
+Function name: overflow::might_overflow
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 07, 01, 09, 05, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 18)
+- Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 5, 2)
+ = (c1 + (c0 - c1))
+
diff --git a/tests/coverage/overflow.coverage b/tests/coverage/overflow.coverage
new file mode 100644
index 000000000..4f8dffc0c
--- /dev/null
+++ b/tests/coverage/overflow.coverage
@@ -0,0 +1,65 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |// compile-flags: -Coverflow-checks=yes
+ LL| |// failure-status: 101
+ LL| |
+ LL| 4|fn might_overflow(to_add: u32) -> u32 {
+ LL| 4| if to_add > 5 {
+ LL| 1| println!("this will probably overflow");
+ LL| 3| }
+ LL| 4| let add_to = u32::MAX - 5;
+ LL| 4| println!("does {} + {} overflow?", add_to, to_add);
+ LL| 4| let result = to_add + add_to;
+ LL| 4| println!("continuing after overflow check");
+ LL| 4| result
+ LL| 4|}
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| let mut countdown = 10;
+ LL| 11| while countdown > 0 {
+ LL| 11| if countdown == 1 {
+ LL| 1| let result = might_overflow(10);
+ LL| 1| println!("Result: {}", result);
+ LL| 10| } else if countdown < 5 {
+ LL| 3| let result = might_overflow(1);
+ LL| 3| println!("Result: {}", result);
+ LL| 6| }
+ LL| 10| countdown -= 1;
+ LL| | }
+ LL| 0| Ok(())
+ LL| 0|}
+ LL| |
+ LL| |// Notes:
+ LL| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`,
+ LL| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`.
+ LL| |// 2. This test confirms the coverage generated when a program passes or fails a
+ LL| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case).
+ LL| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`,
+ LL| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not
+ LL| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as
+ LL| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and
+ LL| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not
+ LL| |// get its own coverage counter.
+ LL| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive.
+ LL| |// In this test, the final count for the statements after the `if` block in `might_overflow()`
+ LL| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending
+ LL| |// on the MIR graph and the structure of the code, this count could have been 3 (which might
+ LL| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before
+ LL| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented
+ LL| |// via StatementKind::Counter at the end of the block, but (as in the case in this test),
+ LL| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on
+ LL| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was
+ LL| |// executed, and counted, 4 times, before reaching the overflow add.
+ LL| |
+ LL| |// If the program did not overflow, the coverage for `might_overflow()` would look like this:
+ LL| |//
+ LL| |// 4| |fn might_overflow(to_add: u32) -> u32 {
+ LL| |// 5| 4| if to_add > 5 {
+ LL| |// 6| 0| println!("this will probably overflow");
+ LL| |// 7| 4| }
+ LL| |// 8| 4| let add_to = u32::MAX - 5;
+ LL| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add);
+ LL| |// 10| 4| let result = to_add + add_to;
+ LL| |// 11| 4| println!("continuing after overflow check");
+ LL| |// 12| 4| result
+ LL| |// 13| 4|}
+
diff --git a/tests/coverage/overflow.rs b/tests/coverage/overflow.rs
new file mode 100644
index 000000000..1c40771b2
--- /dev/null
+++ b/tests/coverage/overflow.rs
@@ -0,0 +1,64 @@
+#![allow(unused_assignments)]
+// compile-flags: -Coverflow-checks=yes
+// failure-status: 101
+
+fn might_overflow(to_add: u32) -> u32 {
+ if to_add > 5 {
+ println!("this will probably overflow");
+ }
+ let add_to = u32::MAX - 5;
+ println!("does {} + {} overflow?", add_to, to_add);
+ let result = to_add + add_to;
+ println!("continuing after overflow check");
+ result
+}
+
+fn main() -> Result<(), u8> {
+ let mut countdown = 10;
+ while countdown > 0 {
+ if countdown == 1 {
+ let result = might_overflow(10);
+ println!("Result: {}", result);
+ } else if countdown < 5 {
+ let result = might_overflow(1);
+ println!("Result: {}", result);
+ }
+ countdown -= 1;
+ }
+ Ok(())
+}
+
+// Notes:
+// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`,
+// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`.
+// 2. This test confirms the coverage generated when a program passes or fails a
+// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case).
+// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`,
+// compiler-generated assertion failures are assumed to be a symptom of a program bug, not
+// expected behavior. To simplify the coverage graphs and keep instrumented programs as
+// small and fast as possible, `Assert` terminators are assumed to always succeed, and
+// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not
+// get its own coverage counter.
+// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive.
+// In this test, the final count for the statements after the `if` block in `might_overflow()`
+// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending
+// on the MIR graph and the structure of the code, this count could have been 3 (which might
+// have been valid for the overflowed add `+`, but should have been 4 for the lines before
+// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented
+// via StatementKind::Counter at the end of the block, but (as in the case in this test),
+// a CounterKind::Expression is always evaluated. In this case, the expression was based on
+// a `Counter` incremented as part of the evaluation of the `if` expression, which was
+// executed, and counted, 4 times, before reaching the overflow add.
+
+// If the program did not overflow, the coverage for `might_overflow()` would look like this:
+//
+// 4| |fn might_overflow(to_add: u32) -> u32 {
+// 5| 4| if to_add > 5 {
+// 6| 0| println!("this will probably overflow");
+// 7| 4| }
+// 8| 4| let add_to = u32::MAX - 5;
+// 9| 4| println!("does {} + {} overflow?", add_to, to_add);
+// 10| 4| let result = to_add + add_to;
+// 11| 4| println!("continuing after overflow check");
+// 12| 4| result
+// 13| 4|}
diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map
new file mode 100644
index 000000000..f6089ce55
--- /dev/null
+++ b/tests/coverage/panic_unwind.cov-map
@@ -0,0 +1,40 @@
+Function name: panic_unwind::main
+Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 8
+- expression 0 operands: lhs = Counter(0), rhs = Expression(6, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(1)
+- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(4)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24)
+ = (c0 + (c1 + (c2 + c3)))
+- Code(Expression(5, Sub)) at (prev + 1, 12) to (start + 0, 26)
+ = ((c0 + (c1 + (c2 + c3))) - c4)
+- Code(Counter(1)) at (prev + 0, 27) to (start + 2, 10)
+- Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32)
+ = (((c0 + (c1 + (c2 + c3))) - c4) - c1)
+- Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10)
+- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23)
+ = (c1 + (c2 + c3))
+- Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2)
+
+Function name: panic_unwind::might_panic
+Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 19, 02, 02, 0c, 03, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20)
+- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 25)
+- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2)
+ = (c0 - c1)
+
diff --git a/tests/coverage/panic_unwind.coverage b/tests/coverage/panic_unwind.coverage
new file mode 100644
index 000000000..2b0777ef2
--- /dev/null
+++ b/tests/coverage/panic_unwind.coverage
@@ -0,0 +1,32 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |// failure-status: 101
+ LL| |
+ LL| 4|fn might_panic(should_panic: bool) {
+ LL| 4| if should_panic {
+ LL| 1| println!("panicking...");
+ LL| 1| panic!("panics");
+ LL| 3| } else {
+ LL| 3| println!("Don't Panic");
+ LL| 3| }
+ LL| 3|}
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| let mut countdown = 10;
+ LL| 11| while countdown > 0 {
+ LL| 11| if countdown == 1 {
+ LL| 1| might_panic(true);
+ LL| 10| } else if countdown < 5 {
+ LL| 3| might_panic(false);
+ LL| 6| }
+ LL| 10| countdown -= 1;
+ LL| | }
+ LL| 0| Ok(())
+ LL| 0|}
+ LL| |
+ LL| |// Notes:
+ LL| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and
+ LL| |// `try_error_result.rs`.
+ LL| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the
+ LL| |// normal program exit cleanup, including writing out the current values of the coverage
+ LL| |// counters.
+
diff --git a/tests/coverage/panic_unwind.rs b/tests/coverage/panic_unwind.rs
new file mode 100644
index 000000000..638d2eb6a
--- /dev/null
+++ b/tests/coverage/panic_unwind.rs
@@ -0,0 +1,31 @@
+#![allow(unused_assignments)]
+// failure-status: 101
+
+fn might_panic(should_panic: bool) {
+ if should_panic {
+ println!("panicking...");
+ panic!("panics");
+ } else {
+ println!("Don't Panic");
+ }
+}
+
+fn main() -> Result<(), u8> {
+ let mut countdown = 10;
+ while countdown > 0 {
+ if countdown == 1 {
+ might_panic(true);
+ } else if countdown < 5 {
+ might_panic(false);
+ }
+ countdown -= 1;
+ }
+ Ok(())
+}
+
+// Notes:
+// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and
+// `try_error_result.rs`.
+// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the
+// normal program exit cleanup, including writing out the current values of the coverage
+// counters.
diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map
new file mode 100644
index 000000000..3549116db
--- /dev/null
+++ b/tests/coverage/partial_eq.cov-map
@@ -0,0 +1,64 @@
+Function name: <partial_eq::Version as core::clone::Clone>::clone (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 04, 0a, 00, 0f]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 4, 10) to (start + 0, 15)
+
+Function name: <partial_eq::Version as core::cmp::Ord>::cmp (unused)
+Raw bytes (14): 0x[01, 01, 00, 02, 00, 04, 33, 00, 34, 00, 00, 35, 00, 36]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Zero) at (prev + 4, 51) to (start + 0, 52)
+- Code(Zero) at (prev + 0, 53) to (start + 0, 54)
+
+Function name: <partial_eq::Version as core::cmp::PartialEq>::eq (unused)
+Raw bytes (14): 0x[01, 01, 00, 02, 00, 04, 18, 00, 19, 00, 00, 20, 00, 21]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Zero) at (prev + 4, 24) to (start + 0, 25)
+- Code(Zero) at (prev + 0, 32) to (start + 0, 33)
+
+Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
+Raw bytes (22): 0x[01, 01, 04, 07, 0b, 05, 09, 0f, 15, 0d, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
+- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
+- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
+ = ((c1 + c2) + ((c3 + c4) + c5))
+
+Function name: <partial_eq::Version as core::fmt::Debug>::fmt
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 4, 17) to (start + 0, 22)
+
+Function name: <partial_eq::Version>::new
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 06, 06]
+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, 5) to (start + 6, 6)
+
+Function name: partial_eq::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 05, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 21, 1) to (start + 5, 2)
+
diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage
new file mode 100644
index 000000000..c6d9ad6cf
--- /dev/null
+++ b/tests/coverage/partial_eq.coverage
@@ -0,0 +1,48 @@
+ LL| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the
+ LL| |// structure of this test.
+ LL| |
+ LL| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+ ^0 ^0 ^0 ^1 ^1 ^0^0
+ LL| |pub struct Version {
+ LL| | major: usize,
+ LL| | minor: usize,
+ LL| | patch: usize,
+ LL| |}
+ LL| |
+ LL| |impl Version {
+ LL| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self {
+ LL| 2| Self {
+ LL| 2| major,
+ LL| 2| minor,
+ LL| 2| patch,
+ LL| 2| }
+ LL| 2| }
+ LL| |}
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let version_3_2_1 = Version::new(3, 2, 1);
+ LL| 1| let version_3_3_0 = Version::new(3, 3, 0);
+ LL| 1|
+ LL| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0);
+ LL| 1|}
+ LL| |
+ LL| |/*
+ LL| |
+ LL| |This test verifies a bug was fixed that otherwise generated this error:
+ LL| |
+ LL| |thread 'rustc' panicked at 'No counters provided the source_hash for function:
+ LL| | Instance {
+ LL| | def: Item(WithOptConstParam {
+ LL| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp),
+ LL| | const_param_did: None
+ LL| | }),
+ LL| | args: []
+ LL| | }'
+ LL| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage
+ LL| |without a code region associated with any `Counter`. Code regions were associated with at least
+ LL| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen
+ LL| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the
+ LL| |`function_source_hash` without a code region, if necessary.
+ LL| |
+ LL| |*/
+
diff --git a/tests/coverage/partial_eq.rs b/tests/coverage/partial_eq.rs
new file mode 100644
index 000000000..dd8b42c18
--- /dev/null
+++ b/tests/coverage/partial_eq.rs
@@ -0,0 +1,46 @@
+// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the
+// structure of this test.
+
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Version {
+ major: usize,
+ minor: usize,
+ patch: usize,
+}
+
+impl Version {
+ pub fn new(major: usize, minor: usize, patch: usize) -> Self {
+ Self {
+ major,
+ minor,
+ patch,
+ }
+ }
+}
+
+fn main() {
+ let version_3_2_1 = Version::new(3, 2, 1);
+ let version_3_3_0 = Version::new(3, 3, 0);
+
+ println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0);
+}
+
+/*
+
+This test verifies a bug was fixed that otherwise generated this error:
+
+thread 'rustc' panicked at 'No counters provided the source_hash for function:
+ Instance {
+ def: Item(WithOptConstParam {
+ did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp),
+ const_param_did: None
+ }),
+ args: []
+ }'
+The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage
+without a code region associated with any `Counter`. Code regions were associated with at least
+one expression, which is allowed, but the `function_source_hash` was only passed to the codegen
+(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the
+`function_source_hash` without a code region, if necessary.
+
+*/
diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map
new file mode 100644
index 000000000..f1691ffc5
--- /dev/null
+++ b/tests/coverage/simple_loop.cov-map
@@ -0,0 +1,27 @@
+Function name: simple_loop::main
+Raw bytes (57): 0x[01, 01, 09, 01, 05, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 07, 01, 03, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 1f, 05, 0d, 02, 0e, 1a, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 1a, 06, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 9
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Expression(8, Add), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 3 operands: lhs = Expression(7, Add), rhs = Counter(2)
+- expression 4 operands: lhs = Expression(8, Add), rhs = Counter(2)
+- expression 5 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(2)
+- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(2)
+- expression 8 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 7
+- Code(Counter(0)) at (prev + 3, 1) to (start + 9, 16)
+- Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6)
+- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(7, Add)) at (prev + 5, 13) to (start + 2, 14)
+ = ((c1 + (c0 - c1)) + c2)
+- Code(Expression(6, Sub)) at (prev + 4, 13) to (start + 0, 18)
+ = (((c1 + (c0 - c1)) + c2) - c2)
+- Code(Counter(2)) at (prev + 2, 10) to (start + 3, 10)
+- Code(Expression(6, Sub)) at (prev + 6, 1) to (start + 0, 2)
+ = (((c1 + (c0 - c1)) + c2) - c2)
+
diff --git a/tests/coverage/simple_loop.coverage b/tests/coverage/simple_loop.coverage
new file mode 100644
index 000000000..691c6cd1e
--- /dev/null
+++ b/tests/coverage/simple_loop.coverage
@@ -0,0 +1,37 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let mut countdown = 0;
+ LL| 1|
+ LL| 1| if
+ LL| 1| is_true
+ LL| 1| {
+ LL| 1| countdown
+ LL| 1| =
+ LL| 1| 10
+ LL| 1| ;
+ LL| 1| }
+ ^0
+ LL| |
+ LL| | loop
+ LL| | {
+ LL| | if
+ LL| 11| countdown
+ LL| 11| ==
+ LL| 11| 0
+ LL| | {
+ LL| 1| break
+ LL| | ;
+ LL| 10| }
+ LL| 10| countdown
+ LL| 10| -=
+ LL| 10| 1
+ LL| | ;
+ LL| | }
+ LL| 1|}
+
diff --git a/tests/coverage/simple_loop.rs b/tests/coverage/simple_loop.rs
new file mode 100644
index 000000000..6f7f23475
--- /dev/null
+++ b/tests/coverage/simple_loop.rs
@@ -0,0 +1,35 @@
+#![allow(unused_assignments)]
+
+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 countdown = 0;
+
+ if
+ is_true
+ {
+ countdown
+ =
+ 10
+ ;
+ }
+
+ loop
+ {
+ if
+ countdown
+ ==
+ 0
+ {
+ break
+ ;
+ }
+ countdown
+ -=
+ 1
+ ;
+ }
+}
diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map
new file mode 100644
index 000000000..4a32745d2
--- /dev/null
+++ b/tests/coverage/simple_match.cov-map
@@ -0,0 +1,33 @@
+Function name: simple_match::main
+Raw bytes (78): 0x[01, 01, 0c, 01, 05, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 0a, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 27, 05, 09, 00, 0d, 22, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 22, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 12
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
+- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 4 operands: lhs = Expression(9, Add), rhs = Counter(4)
+- expression 5 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(4)
+- expression 9 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
+- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 10
+- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15)
+- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(9, Add)) at (prev + 5, 9) to (start + 0, 13)
+ = ((c1 + (c0 - c1)) + (c2 + c3))
+- Code(Expression(8, Sub)) at (prev + 5, 13) to (start + 0, 22)
+ = (((c1 + (c0 - c1)) + (c2 + c3)) - c4)
+- Code(Counter(2)) at (prev + 2, 13) to (start + 0, 14)
+- Code(Expression(8, Sub)) at (prev + 2, 17) to (start + 2, 18)
+ = (((c1 + (c0 - c1)) + (c2 + c3)) - c4)
+- Code(Counter(2)) at (prev + 4, 13) to (start + 7, 14)
+- Code(Counter(3)) at (prev + 10, 13) to (start + 0, 15)
+- Code(Counter(4)) at (prev + 3, 1) to (start + 0, 2)
+
diff --git a/tests/coverage/simple_match.coverage b/tests/coverage/simple_match.coverage
new file mode 100644
index 000000000..7f5dd3bb6
--- /dev/null
+++ b/tests/coverage/simple_match.coverage
@@ -0,0 +1,45 @@
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1|
+ LL| 1| let mut countdown = 1;
+ LL| 1| if is_true {
+ LL| 1| countdown = 0;
+ LL| 1| }
+ ^0
+ LL| |
+ LL| | for
+ LL| | _
+ LL| | in
+ LL| 3| 0..2
+ LL| | {
+ LL| | let z
+ LL| | ;
+ LL| | match
+ LL| 2| countdown
+ LL| | {
+ LL| 1| x
+ LL| | if
+ LL| 2| x
+ LL| 2| <
+ LL| 2| 1
+ LL| | =>
+ LL| 1| {
+ LL| 1| z = countdown
+ LL| 1| ;
+ LL| 1| let y = countdown
+ LL| 1| ;
+ LL| 1| countdown = 10
+ LL| 1| ;
+ LL| 1| }
+ LL| | _
+ LL| | =>
+ LL| 1| {}
+ LL| | }
+ LL| | }
+ LL| 1|}
+
diff --git a/tests/coverage/simple_match.rs b/tests/coverage/simple_match.rs
new file mode 100644
index 000000000..be99e59a8
--- /dev/null
+++ b/tests/coverage/simple_match.rs
@@ -0,0 +1,43 @@
+#![allow(unused_assignments, unused_variables)]
+
+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 countdown = 1;
+ if is_true {
+ countdown = 0;
+ }
+
+ for
+ _
+ in
+ 0..2
+ {
+ let z
+ ;
+ match
+ countdown
+ {
+ x
+ if
+ x
+ <
+ 1
+ =>
+ {
+ z = countdown
+ ;
+ let y = countdown
+ ;
+ countdown = 10
+ ;
+ }
+ _
+ =>
+ {}
+ }
+ }
+}
diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map
new file mode 100644
index 000000000..3cbda6fbe
--- /dev/null
+++ b/tests/coverage/sort_groups.cov-map
@@ -0,0 +1,83 @@
+Function name: sort_groups::generic_fn::<&str>
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
+- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: sort_groups::generic_fn::<()>
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
+- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: sort_groups::generic_fn::<char>
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
+- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: sort_groups::generic_fn::<i32>
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
+- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: sort_groups::main
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 06, 01, 04, 23, 05, 04, 24, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 6, 1) to (start + 4, 35)
+- Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 2, 2)
+ = (c1 + (c0 - c1))
+
+Function name: sort_groups::other_fn
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 17)
+
diff --git a/tests/coverage/sort_groups.coverage b/tests/coverage/sort_groups.coverage
new file mode 100644
index 000000000..c70d7b3b2
--- /dev/null
+++ b/tests/coverage/sort_groups.coverage
@@ -0,0 +1,49 @@
+ LL| |// compile-flags: --edition=2021
+ LL| |
+ LL| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a
+ LL| |// predictable order, while preserving their heterogeneous contents.
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let cond = std::env::args().len() > 1;
+ LL| 1| generic_fn::<()>(cond);
+ LL| 1| generic_fn::<&'static str>(!cond);
+ LL| 1| if std::hint::black_box(false) {
+ LL| 0| generic_fn::<char>(cond);
+ LL| 1| }
+ LL| 1| generic_fn::<i32>(cond);
+ LL| 1| other_fn();
+ LL| 1|}
+ LL| |
+ LL| 3|fn generic_fn<T>(cond: bool) {
+ LL| 3| if cond {
+ LL| 1| println!("{}", std::any::type_name::<T>());
+ LL| 2| }
+ LL| 3|}
+ ------------------
+ | Unexecuted instantiation: sort_groups::generic_fn::<char>
+ ------------------
+ | sort_groups::generic_fn::<&str>:
+ | LL| 1|fn generic_fn<T>(cond: bool) {
+ | LL| 1| if cond {
+ | LL| 1| println!("{}", std::any::type_name::<T>());
+ | LL| 1| }
+ | ^0
+ | LL| 1|}
+ ------------------
+ | sort_groups::generic_fn::<()>:
+ | LL| 1|fn generic_fn<T>(cond: bool) {
+ | LL| 1| if cond {
+ | LL| 0| println!("{}", std::any::type_name::<T>());
+ | LL| 1| }
+ | LL| 1|}
+ ------------------
+ | sort_groups::generic_fn::<i32>:
+ | LL| 1|fn generic_fn<T>(cond: bool) {
+ | LL| 1| if cond {
+ | LL| 0| println!("{}", std::any::type_name::<T>());
+ | LL| 1| }
+ | LL| 1|}
+ ------------------
+ LL| |
+ LL| 1|fn other_fn() {}
+
diff --git a/tests/coverage/sort_groups.rs b/tests/coverage/sort_groups.rs
new file mode 100644
index 000000000..5adbbc6a8
--- /dev/null
+++ b/tests/coverage/sort_groups.rs
@@ -0,0 +1,23 @@
+// compile-flags: --edition=2021
+
+// Demonstrate that `sort_subviews.py` can sort instantiation groups into a
+// predictable order, while preserving their heterogeneous contents.
+
+fn main() {
+ let cond = std::env::args().len() > 1;
+ generic_fn::<()>(cond);
+ generic_fn::<&'static str>(!cond);
+ if std::hint::black_box(false) {
+ generic_fn::<char>(cond);
+ }
+ generic_fn::<i32>(cond);
+ other_fn();
+}
+
+fn generic_fn<T>(cond: bool) {
+ if cond {
+ println!("{}", std::any::type_name::<T>());
+ }
+}
+
+fn other_fn() {}
diff --git a/tests/coverage/test_harness.cov-map b/tests/coverage/test_harness.cov-map
new file mode 100644
index 000000000..6940d2e28
--- /dev/null
+++ b/tests/coverage/test_harness.cov-map
@@ -0,0 +1,24 @@
+Function name: test_harness::my_test
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 00, 10]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16)
+
+Function name: test_harness::my_test::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 01, 00, 08]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 8)
+
+Function name: test_harness::unused (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 07, 01, 00, 0f]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 7, 1) to (start + 0, 15)
+
diff --git a/tests/coverage/test_harness.coverage b/tests/coverage/test_harness.coverage
new file mode 100644
index 000000000..ff6009f6f
--- /dev/null
+++ b/tests/coverage/test_harness.coverage
@@ -0,0 +1,11 @@
+ LL| |// Verify that the entry point injected by the test harness doesn't cause
+ LL| |// weird artifacts in the coverage report (e.g. issue #10749).
+ LL| |
+ LL| |// compile-flags: --test
+ LL| |
+ LL| |#[allow(dead_code)]
+ LL| 0|fn unused() {}
+ LL| |
+ LL| 1|#[test]
+ LL| 1|fn my_test() {}
+
diff --git a/tests/coverage/test_harness.rs b/tests/coverage/test_harness.rs
new file mode 100644
index 000000000..12a755734
--- /dev/null
+++ b/tests/coverage/test_harness.rs
@@ -0,0 +1,10 @@
+// Verify that the entry point injected by the test harness doesn't cause
+// weird artifacts in the coverage report (e.g. issue #10749).
+
+// compile-flags: --test
+
+#[allow(dead_code)]
+fn unused() {}
+
+#[test]
+fn my_test() {}
diff --git a/tests/coverage/tight_inf_loop.cov-map b/tests/coverage/tight_inf_loop.cov-map
new file mode 100644
index 000000000..7fe3146b0
--- /dev/null
+++ b/tests/coverage/tight_inf_loop.cov-map
@@ -0,0 +1,12 @@
+Function name: tight_inf_loop::main
+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 = 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 - Zero)
+
diff --git a/tests/coverage/tight_inf_loop.coverage b/tests/coverage/tight_inf_loop.coverage
new file mode 100644
index 000000000..c15c76b3a
--- /dev/null
+++ b/tests/coverage/tight_inf_loop.coverage
@@ -0,0 +1,6 @@
+ LL| 1|fn main() {
+ LL| 1| if false {
+ LL| 0| loop {}
+ LL| 1| }
+ LL| 1|}
+
diff --git a/tests/coverage/tight_inf_loop.rs b/tests/coverage/tight_inf_loop.rs
new file mode 100644
index 000000000..cef99027a
--- /dev/null
+++ b/tests/coverage/tight_inf_loop.rs
@@ -0,0 +1,5 @@
+fn main() {
+ if false {
+ loop {}
+ }
+}
diff --git a/tests/coverage/trivial.cov-map b/tests/coverage/trivial.cov-map
new file mode 100644
index 000000000..874e294a1
--- /dev/null
+++ b/tests/coverage/trivial.cov-map
@@ -0,0 +1,8 @@
+Function name: trivial::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13)
+
diff --git a/tests/coverage/trivial.coverage b/tests/coverage/trivial.coverage
new file mode 100644
index 000000000..4f417979e
--- /dev/null
+++ b/tests/coverage/trivial.coverage
@@ -0,0 +1,4 @@
+ LL| |// compile-flags: --edition=2021
+ LL| |
+ LL| 1|fn main() {}
+
diff --git a/tests/coverage/trivial.rs b/tests/coverage/trivial.rs
new file mode 100644
index 000000000..d0a9b44fb
--- /dev/null
+++ b/tests/coverage/trivial.rs
@@ -0,0 +1,3 @@
+// compile-flags: --edition=2021
+
+fn main() {}
diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map
new file mode 100644
index 000000000..8367103a2
--- /dev/null
+++ b/tests/coverage/try_error_result.cov-map
@@ -0,0 +1,220 @@
+Function name: <try_error_result::Thing1>::get_thing_2
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 28, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 07, 02, 05, 00, 06]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 40, 5) to (start + 1, 24)
+- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20)
+- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
+ = (c1 + (c0 - c1))
+
+Function name: <try_error_result::Thing2>::call
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 33, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 07, 02, 05, 00, 06]
+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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 51, 5) to (start + 1, 24)
+- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20)
+- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
+ = (c1 + (c0 - c1))
+
+Function name: try_error_result::call
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20)
+- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16)
+- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: try_error_result::main
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 70, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 112, 1) to (start + 2, 12)
+- Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = (c1 + (c0 - c1))
+
+Function name: try_error_result::test1
+Raw bytes (77): 0x[01, 01, 09, 01, 07, 05, 09, 03, 0d, 1d, 11, 16, 1d, 03, 0d, 1f, 0d, 11, 23, 15, 19, 0b, 01, 0c, 01, 02, 17, 03, 07, 09, 00, 0e, 16, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 0e, 01, 0d, 00, 2a, 15, 00, 2a, 00, 2b, 12, 04, 0d, 00, 2a, 19, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 1b, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 9
+- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(7), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(7)
+- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(3)
+- expression 7 operands: lhs = Counter(4), rhs = Expression(8, Add)
+- expression 8 operands: lhs = Counter(5), rhs = Counter(6)
+Number of file 0 mappings: 11
+- Code(Counter(0)) at (prev + 12, 1) to (start + 2, 23)
+- Code(Expression(0, Add)) at (prev + 7, 9) to (start + 0, 14)
+ = (c0 + (c1 + c2))
+- Code(Expression(5, Sub)) at (prev + 2, 9) to (start + 4, 26)
+ = ((c0 + (c1 + c2)) - c3)
+- Code(Counter(7)) at (prev + 6, 13) to (start + 0, 41)
+- Code(Counter(4)) at (prev + 0, 41) to (start + 0, 42)
+- Code(Expression(3, Sub)) at (prev + 1, 13) to (start + 0, 42)
+ = (c7 - c4)
+- Code(Counter(5)) at (prev + 0, 42) to (start + 0, 43)
+- Code(Expression(4, Sub)) at (prev + 4, 13) to (start + 0, 42)
+ = (((c0 + (c1 + c2)) - c3) - c7)
+- Code(Counter(6)) at (prev + 0, 42) to (start + 0, 43)
+- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11)
+- Code(Expression(6, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = ((c4 + (c5 + c6)) + c3)
+
+Function name: try_error_result::test2
+Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, 11, c7, 01, cb, 01, db, 01, 15, cf, 01, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3c, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 59
+- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 5 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(7)
+- expression 7 operands: lhs = Expression(17, Sub), rhs = Counter(6)
+- expression 8 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 9 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 10 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 11 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 12 operands: lhs = Expression(17, Sub), rhs = Counter(6)
+- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 14 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(7)
+- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(6)
+- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(5)
+- expression 18 operands: lhs = Counter(16), rhs = Counter(4)
+- expression 19 operands: lhs = Expression(23, Sub), rhs = Counter(9)
+- expression 20 operands: lhs = Counter(18), rhs = Counter(8)
+- expression 21 operands: lhs = Counter(18), rhs = Counter(8)
+- expression 22 operands: lhs = Expression(23, Sub), rhs = Counter(9)
+- expression 23 operands: lhs = Counter(18), rhs = Counter(8)
+- expression 24 operands: lhs = Expression(34, Sub), rhs = Counter(11)
+- expression 25 operands: lhs = Expression(35, Sub), rhs = Counter(10)
+- expression 26 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 27 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 28 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 29 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 30 operands: lhs = Expression(35, Sub), rhs = Counter(10)
+- expression 31 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 32 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 33 operands: lhs = Expression(34, Sub), rhs = Counter(11)
+- expression 34 operands: lhs = Expression(35, Sub), rhs = Counter(10)
+- expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(16)
+- expression 36 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 37 operands: lhs = Expression(41, Sub), rhs = Counter(13)
+- expression 38 operands: lhs = Counter(17), rhs = Counter(12)
+- expression 39 operands: lhs = Counter(17), rhs = Counter(12)
+- expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(13)
+- expression 41 operands: lhs = Counter(17), rhs = Counter(12)
+- expression 42 operands: lhs = Expression(46, Sub), rhs = Counter(15)
+- expression 43 operands: lhs = Counter(19), rhs = Counter(14)
+- expression 44 operands: lhs = Counter(19), rhs = Counter(14)
+- expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(15)
+- expression 46 operands: lhs = Counter(19), rhs = Counter(14)
+- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(3)
+- expression 48 operands: lhs = Counter(4), rhs = Expression(49, Add)
+- expression 49 operands: lhs = Expression(50, Add), rhs = Expression(54, Add)
+- expression 50 operands: lhs = Counter(5), rhs = Expression(51, Add)
+- expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add)
+- expression 52 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 53 operands: lhs = Counter(8), rhs = Counter(9)
+- expression 54 operands: lhs = Expression(55, Add), rhs = Expression(56, Add)
+- expression 55 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 56 operands: lhs = Expression(57, Add), rhs = Expression(58, Add)
+- expression 57 operands: lhs = Counter(12), rhs = Counter(13)
+- expression 58 operands: lhs = Counter(14), rhs = Counter(15)
+Number of file 0 mappings: 40
+- Code(Counter(0)) at (prev + 60, 1) to (start + 3, 23)
+- Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14)
+ = (c0 + (c1 + c2))
+- Code(Expression(36, Sub)) at (prev + 2, 9) to (start + 4, 26)
+ = ((c0 + (c1 + c2)) - c3)
+- Code(Counter(16)) at (prev + 6, 13) to (start + 0, 47)
+- Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48)
+- Code(Expression(18, Sub)) at (prev + 0, 49) to (start + 3, 53)
+ = (c16 - c4)
+- Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18)
+- Code(Expression(17, Sub)) at (prev + 2, 17) to (start + 4, 18)
+ = ((c16 - c4) - c5)
+- Code(Expression(15, Sub)) at (prev + 5, 17) to (start + 0, 20)
+ = ((((c16 - c4) - c5) - c6) - c7)
+- Code(Expression(17, Sub)) at (prev + 0, 23) to (start + 0, 65)
+ = ((c16 - c4) - c5)
+- Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66)
+- Code(Expression(16, Sub)) at (prev + 0, 67) to (start + 0, 95)
+ = (((c16 - c4) - c5) - c6)
+- Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96)
+- Code(Expression(15, Sub)) at (prev + 1, 13) to (start + 0, 32)
+ = ((((c16 - c4) - c5) - c6) - c7)
+- Code(Expression(22, Sub)) at (prev + 1, 17) to (start + 0, 20)
+ = ((c18 - c8) - c9)
+- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 65)
+- Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66)
+- Code(Expression(23, Sub)) at (prev + 0, 67) to (start + 0, 96)
+ = (c18 - c8)
+- Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97)
+- Code(Expression(22, Sub)) at (prev + 1, 13) to (start + 0, 32)
+ = ((c18 - c8) - c9)
+- Code(Expression(33, Sub)) at (prev + 4, 17) to (start + 0, 20)
+ = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11)
+- Code(Expression(35, Sub)) at (prev + 0, 23) to (start + 0, 66)
+ = (((c0 + (c1 + c2)) - c3) - c16)
+- Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67)
+- Code(Expression(34, Sub)) at (prev + 0, 68) to (start + 0, 97)
+ = ((((c0 + (c1 + c2)) - c3) - c16) - c10)
+- Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98)
+- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 32)
+ = (((((c0 + (c1 + c2)) - c3) - c16) - c10) - c11)
+- Code(Expression(40, Sub)) at (prev + 1, 17) to (start + 0, 20)
+ = ((c17 - c12) - c13)
+- Code(Counter(17)) at (prev + 0, 23) to (start + 1, 54)
+- Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55)
+- Code(Expression(41, Sub)) at (prev + 1, 18) to (start + 0, 47)
+ = (c17 - c12)
+- Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48)
+- Code(Expression(40, Sub)) at (prev + 1, 13) to (start + 0, 32)
+ = ((c17 - c12) - c13)
+- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20)
+ = ((c19 - c14) - c15)
+- Code(Counter(19)) at (prev + 0, 23) to (start + 1, 54)
+- Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18)
+- Code(Expression(46, Sub)) at (prev + 1, 18) to (start + 0, 47)
+ = (c19 - c14)
+- Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18)
+- Code(Expression(45, Sub)) at (prev + 2, 13) to (start + 0, 32)
+ = ((c19 - c14) - c15)
+- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11)
+- Code(Expression(47, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = ((c4 + ((c5 + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15))))) + c3)
+
diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/try_error_result.coverage
new file mode 100644
index 000000000..5d48cbd62
--- /dev/null
+++ b/tests/coverage/try_error_result.coverage
@@ -0,0 +1,125 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |// failure-status: 1
+ LL| |
+ LL| 6|fn call(return_error: bool) -> Result<(), ()> {
+ LL| 6| if return_error {
+ LL| 1| Err(())
+ LL| | } else {
+ LL| 5| Ok(())
+ LL| | }
+ LL| 6|}
+ LL| |
+ LL| 1|fn test1() -> Result<(), ()> {
+ LL| 1| let mut
+ LL| 1| countdown = 10
+ LL| | ;
+ LL| | for
+ LL| | _
+ LL| | in
+ LL| 6| 0..10
+ LL| | {
+ LL| 6| countdown
+ LL| 6| -= 1
+ LL| 6| ;
+ LL| 6| if
+ LL| 6| countdown < 5
+ LL| | {
+ LL| 1| call(/*return_error=*/ true)?;
+ LL| 0| call(/*return_error=*/ false)?;
+ LL| | }
+ LL| | else
+ LL| | {
+ LL| 5| call(/*return_error=*/ false)?;
+ ^0
+ LL| | }
+ LL| | }
+ LL| 0| Ok(())
+ LL| 1|}
+ LL| |
+ LL| |struct Thing1;
+ LL| |impl Thing1 {
+ LL| 18| fn get_thing_2(&self, return_error: bool) -> Result<Thing2, ()> {
+ LL| 18| if return_error {
+ LL| 1| Err(())
+ LL| | } else {
+ LL| 17| Ok(Thing2 {})
+ LL| | }
+ LL| 18| }
+ LL| |}
+ LL| |
+ LL| |struct Thing2;
+ LL| |impl Thing2 {
+ LL| 17| fn call(&self, return_error: bool) -> Result<u32, ()> {
+ LL| 17| if return_error {
+ LL| 2| Err(())
+ LL| | } else {
+ LL| 15| Ok(57)
+ LL| | }
+ LL| 17| }
+ LL| |}
+ LL| |
+ LL| 1|fn test2() -> Result<(), ()> {
+ LL| 1| let thing1 = Thing1{};
+ LL| 1| let mut
+ LL| 1| countdown = 10
+ LL| | ;
+ LL| | for
+ LL| | _
+ LL| | in
+ LL| 6| 0..10
+ LL| | {
+ LL| 6| countdown
+ LL| 6| -= 1
+ LL| 6| ;
+ LL| 6| if
+ LL| 6| countdown < 5
+ LL| | {
+ LL| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+ ^0
+ LL| 1| thing1
+ LL| 1| .
+ LL| 1| get_thing_2(/*return_error=*/ false)
+ LL| 0| ?
+ LL| | .
+ LL| 1| call(/*return_error=*/ true)
+ LL| 1| .
+ LL| 1| expect_err(
+ LL| 1| "call should fail"
+ LL| 1| );
+ LL| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+ ^0 ^0 ^0
+ LL| 0| assert_eq!(val, 57);
+ LL| 0| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+ LL| 0| assert_eq!(val, 57);
+ LL| | }
+ LL| | else
+ LL| | {
+ LL| 5| let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+ ^0 ^0
+ LL| 5| assert_eq!(val, 57);
+ LL| 5| let val = thing1
+ LL| 5| .get_thing_2(/*return_error=*/ false)?
+ ^0
+ LL| 5| .call(/*return_error=*/ false)?;
+ ^0
+ LL| 5| assert_eq!(val, 57);
+ LL| 5| let val = thing1
+ LL| 5| .get_thing_2(/*return_error=*/ false)
+ LL| 0| ?
+ LL| 5| .call(/*return_error=*/ false)
+ LL| 0| ?
+ LL| | ;
+ LL| 5| assert_eq!(val, 57);
+ LL| | }
+ LL| | }
+ LL| 0| Ok(())
+ LL| 1|}
+ LL| |
+ LL| 1|fn main() -> Result<(), ()> {
+ LL| 1| test1().expect_err("test1 should fail");
+ LL| 1| test2()
+ LL| 1| ?
+ LL| | ;
+ LL| 0| Ok(())
+ LL| 1|}
+
diff --git a/tests/coverage/try_error_result.rs b/tests/coverage/try_error_result.rs
new file mode 100644
index 000000000..557cbf22b
--- /dev/null
+++ b/tests/coverage/try_error_result.rs
@@ -0,0 +1,118 @@
+#![allow(unused_assignments)]
+// failure-status: 1
+
+fn call(return_error: bool) -> Result<(), ()> {
+ if return_error {
+ Err(())
+ } else {
+ Ok(())
+ }
+}
+
+fn test1() -> Result<(), ()> {
+ let mut
+ countdown = 10
+ ;
+ for
+ _
+ in
+ 0..10
+ {
+ countdown
+ -= 1
+ ;
+ if
+ countdown < 5
+ {
+ call(/*return_error=*/ true)?;
+ call(/*return_error=*/ false)?;
+ }
+ else
+ {
+ call(/*return_error=*/ false)?;
+ }
+ }
+ Ok(())
+}
+
+struct Thing1;
+impl Thing1 {
+ fn get_thing_2(&self, return_error: bool) -> Result<Thing2, ()> {
+ if return_error {
+ Err(())
+ } else {
+ Ok(Thing2 {})
+ }
+ }
+}
+
+struct Thing2;
+impl Thing2 {
+ fn call(&self, return_error: bool) -> Result<u32, ()> {
+ if return_error {
+ Err(())
+ } else {
+ Ok(57)
+ }
+ }
+}
+
+fn test2() -> Result<(), ()> {
+ let thing1 = Thing1{};
+ let mut
+ countdown = 10
+ ;
+ for
+ _
+ in
+ 0..10
+ {
+ countdown
+ -= 1
+ ;
+ if
+ countdown < 5
+ {
+ thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+ thing1
+ .
+ get_thing_2(/*return_error=*/ false)
+ ?
+ .
+ call(/*return_error=*/ true)
+ .
+ expect_err(
+ "call should fail"
+ );
+ let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+ assert_eq!(val, 57);
+ let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+ assert_eq!(val, 57);
+ }
+ else
+ {
+ let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+ assert_eq!(val, 57);
+ let val = thing1
+ .get_thing_2(/*return_error=*/ false)?
+ .call(/*return_error=*/ false)?;
+ assert_eq!(val, 57);
+ let val = thing1
+ .get_thing_2(/*return_error=*/ false)
+ ?
+ .call(/*return_error=*/ false)
+ ?
+ ;
+ assert_eq!(val, 57);
+ }
+ }
+ Ok(())
+}
+
+fn main() -> Result<(), ()> {
+ test1().expect_err("test1 should fail");
+ test2()
+ ?
+ ;
+ Ok(())
+}
diff --git a/tests/coverage/unreachable.cov-map b/tests/coverage/unreachable.cov-map
new file mode 100644
index 000000000..495419820
--- /dev/null
+++ b/tests/coverage/unreachable.cov-map
@@ -0,0 +1,24 @@
+Function name: unreachable::UNREACHABLE_CLOSURE::{closure#0}
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 27, 00, 49]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 15, 39) to (start + 0, 73)
+
+Function name: unreachable::unreachable_function
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 17, 1) to (start + 2, 2)
+
+Function name: unreachable::unreachable_intrinsic
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 22, 1) to (start + 2, 2)
+
diff --git a/tests/coverage/unreachable.coverage b/tests/coverage/unreachable.coverage
new file mode 100644
index 000000000..fa0ac9ccf
--- /dev/null
+++ b/tests/coverage/unreachable.coverage
@@ -0,0 +1,38 @@
+ LL| |#![feature(core_intrinsics)]
+ LL| |#![feature(coverage_attribute)]
+ LL| |// compile-flags: --edition=2021
+ LL| |
+ LL| |// <https://github.com/rust-lang/rust/issues/116171>
+ LL| |// If we instrument a function for coverage, but all of its counter-increment
+ LL| |// statements are removed by MIR optimizations, LLVM will think it isn't
+ LL| |// instrumented and it will disappear from coverage maps and coverage reports.
+ LL| |// Most MIR opts won't cause this because they tend not to remove statements
+ LL| |// from bb0, but `UnreachablePropagation` can do so if it sees that bb0 ends
+ LL| |// with `TerminatorKind::Unreachable`.
+ LL| |
+ LL| |use std::hint::{black_box, unreachable_unchecked};
+ LL| |
+ LL| 0|static UNREACHABLE_CLOSURE: fn() = || unsafe { unreachable_unchecked() };
+ LL| |
+ LL| 0|fn unreachable_function() {
+ LL| 0| unsafe { unreachable_unchecked() }
+ LL| 0|}
+ LL| |
+ LL| |// Use an intrinsic to more reliably trigger unreachable-propagation.
+ LL| 0|fn unreachable_intrinsic() {
+ LL| 0| unsafe { std::intrinsics::unreachable() }
+ LL| 0|}
+ LL| |
+ LL| |#[coverage(off)]
+ LL| |fn main() {
+ LL| | if black_box(false) {
+ LL| | UNREACHABLE_CLOSURE();
+ LL| | }
+ LL| | if black_box(false) {
+ LL| | unreachable_function();
+ LL| | }
+ LL| | if black_box(false) {
+ LL| | unreachable_intrinsic();
+ LL| | }
+ LL| |}
+
diff --git a/tests/coverage/unreachable.rs b/tests/coverage/unreachable.rs
new file mode 100644
index 000000000..6385bfa16
--- /dev/null
+++ b/tests/coverage/unreachable.rs
@@ -0,0 +1,37 @@
+#![feature(core_intrinsics)]
+#![feature(coverage_attribute)]
+// compile-flags: --edition=2021
+
+// <https://github.com/rust-lang/rust/issues/116171>
+// If we instrument a function for coverage, but all of its counter-increment
+// statements are removed by MIR optimizations, LLVM will think it isn't
+// instrumented and it will disappear from coverage maps and coverage reports.
+// Most MIR opts won't cause this because they tend not to remove statements
+// from bb0, but `UnreachablePropagation` can do so if it sees that bb0 ends
+// with `TerminatorKind::Unreachable`.
+
+use std::hint::{black_box, unreachable_unchecked};
+
+static UNREACHABLE_CLOSURE: fn() = || unsafe { unreachable_unchecked() };
+
+fn unreachable_function() {
+ unsafe { unreachable_unchecked() }
+}
+
+// Use an intrinsic to more reliably trigger unreachable-propagation.
+fn unreachable_intrinsic() {
+ unsafe { std::intrinsics::unreachable() }
+}
+
+#[coverage(off)]
+fn main() {
+ if black_box(false) {
+ UNREACHABLE_CLOSURE();
+ }
+ if black_box(false) {
+ unreachable_function();
+ }
+ if black_box(false) {
+ unreachable_intrinsic();
+ }
+}
diff --git a/tests/coverage/unused.cov-map b/tests/coverage/unused.cov-map
new file mode 100644
index 000000000..9383d1e90
--- /dev/null
+++ b/tests/coverage/unused.cov-map
@@ -0,0 +1,94 @@
+Function name: unused::foo::<f32>
+Raw bytes (42): 0x[01, 01, 04, 01, 0f, 05, 09, 03, 0d, 05, 09, 06, 01, 03, 01, 01, 12, 03, 02, 0b, 00, 11, 0a, 01, 09, 00, 0f, 09, 00, 13, 00, 19, 0f, 01, 09, 00, 0f, 0d, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(0), rhs = Expression(3, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 17)
+ = (c0 + (c1 + c2))
+- Code(Expression(2, Sub)) at (prev + 1, 9) to (start + 0, 15)
+ = ((c0 + (c1 + c2)) - c3)
+- Code(Counter(2)) at (prev + 0, 19) to (start + 0, 25)
+- Code(Expression(3, Add)) at (prev + 1, 9) to (start + 0, 15)
+ = (c1 + c2)
+- Code(Counter(3)) at (prev + 2, 1) to (start + 0, 2)
+
+Function name: unused::foo::<u32>
+Raw bytes (42): 0x[01, 01, 04, 01, 0f, 05, 09, 03, 0d, 05, 09, 06, 01, 03, 01, 01, 12, 03, 02, 0b, 00, 11, 0a, 01, 09, 00, 0f, 09, 00, 13, 00, 19, 0f, 01, 09, 00, 0f, 0d, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(0), rhs = Expression(3, Add)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+Number of file 0 mappings: 6
+- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18)
+- Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 17)
+ = (c0 + (c1 + c2))
+- Code(Expression(2, Sub)) at (prev + 1, 9) to (start + 0, 15)
+ = ((c0 + (c1 + c2)) - c3)
+- Code(Counter(2)) at (prev + 0, 19) to (start + 0, 25)
+- Code(Expression(3, Add)) at (prev + 1, 9) to (start + 0, 15)
+ = (c1 + c2)
+- Code(Counter(3)) at (prev + 2, 1) to (start + 0, 2)
+
+Function name: unused::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 04, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 37, 1) to (start + 4, 2)
+
+Function name: unused::unused_func (unused)
+Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Zero) at (prev + 19, 1) to (start + 1, 14)
+- Code(Zero) at (prev + 1, 15) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
+
+Function name: unused::unused_func2 (unused)
+Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Zero) at (prev + 25, 1) to (start + 1, 14)
+- Code(Zero) at (prev + 1, 15) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
+
+Function name: unused::unused_func3 (unused)
+Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Zero) at (prev + 31, 1) to (start + 1, 14)
+- Code(Zero) at (prev + 1, 15) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
+
+Function name: unused::unused_template_func::<_> (unused)
+Raw bytes (34): 0x[01, 01, 00, 06, 00, 0b, 01, 01, 12, 00, 02, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 6
+- Code(Zero) at (prev + 11, 1) to (start + 1, 18)
+- Code(Zero) at (prev + 2, 11) to (start + 0, 17)
+- Code(Zero) at (prev + 1, 9) to (start + 0, 15)
+- Code(Zero) at (prev + 0, 19) to (start + 0, 25)
+- Code(Zero) at (prev + 1, 9) to (start + 0, 15)
+- Code(Zero) at (prev + 2, 1) to (start + 0, 2)
+
diff --git a/tests/coverage/unused.coverage b/tests/coverage/unused.coverage
new file mode 100644
index 000000000..056ffeb02
--- /dev/null
+++ b/tests/coverage/unused.coverage
@@ -0,0 +1,64 @@
+ LL| |#![allow(dead_code, unused_assignments, unused_must_use, unused_variables)]
+ LL| |
+ LL| 2|fn foo<T>(x: T) {
+ LL| 2| let mut i = 0;
+ LL| 22| while i < 10 {
+ LL| 20| i != 0 || i != 0;
+ ^2
+ LL| 20| i += 1;
+ LL| | }
+ LL| 2|}
+ ------------------
+ | unused::foo::<f32>:
+ | LL| 1|fn foo<T>(x: T) {
+ | LL| 1| let mut i = 0;
+ | LL| 11| while i < 10 {
+ | LL| 10| i != 0 || i != 0;
+ | ^1
+ | LL| 10| i += 1;
+ | LL| | }
+ | LL| 1|}
+ ------------------
+ | unused::foo::<u32>:
+ | LL| 1|fn foo<T>(x: T) {
+ | LL| 1| let mut i = 0;
+ | LL| 11| while i < 10 {
+ | LL| 10| i != 0 || i != 0;
+ | ^1
+ | LL| 10| i += 1;
+ | LL| | }
+ | LL| 1|}
+ ------------------
+ LL| |
+ LL| 0|fn unused_template_func<T>(x: T) {
+ LL| 0| let mut i = 0;
+ LL| 0| while i < 10 {
+ LL| 0| i != 0 || i != 0;
+ LL| 0| i += 1;
+ LL| | }
+ LL| 0|}
+ LL| |
+ LL| 0|fn unused_func(mut a: u32) {
+ LL| 0| if a != 0 {
+ LL| 0| a += 1;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| 0|fn unused_func2(mut a: u32) {
+ LL| 0| if a != 0 {
+ LL| 0| a += 1;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| 0|fn unused_func3(mut a: u32) {
+ LL| 0| if a != 0 {
+ LL| 0| a += 1;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| foo::<u32>(0);
+ LL| 1| foo::<f32>(0.0);
+ LL| 1| Ok(())
+ LL| 1|}
+
diff --git a/tests/coverage/unused.rs b/tests/coverage/unused.rs
new file mode 100644
index 000000000..d985af135
--- /dev/null
+++ b/tests/coverage/unused.rs
@@ -0,0 +1,41 @@
+#![allow(dead_code, unused_assignments, unused_must_use, unused_variables)]
+
+fn foo<T>(x: T) {
+ let mut i = 0;
+ while i < 10 {
+ i != 0 || i != 0;
+ i += 1;
+ }
+}
+
+fn unused_template_func<T>(x: T) {
+ let mut i = 0;
+ while i < 10 {
+ i != 0 || i != 0;
+ i += 1;
+ }
+}
+
+fn unused_func(mut a: u32) {
+ if a != 0 {
+ a += 1;
+ }
+}
+
+fn unused_func2(mut a: u32) {
+ if a != 0 {
+ a += 1;
+ }
+}
+
+fn unused_func3(mut a: u32) {
+ if a != 0 {
+ a += 1;
+ }
+}
+
+fn main() -> Result<(), u8> {
+ foo::<u32>(0);
+ foo::<f32>(0.0);
+ Ok(())
+}
diff --git a/tests/coverage/unused_mod.cov-map b/tests/coverage/unused_mod.cov-map
new file mode 100644
index 000000000..241cb2610
--- /dev/null
+++ b/tests/coverage/unused_mod.cov-map
@@ -0,0 +1,16 @@
+Function name: unused_mod::main
+Raw bytes (9): 0x[01, 02, 00, 01, 01, 04, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 2
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 2)
+
+Function name: unused_mod::unused_module::never_called_function (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 02, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 2, 1) to (start + 2, 2)
+
diff --git a/tests/coverage/unused_mod.coverage b/tests/coverage/unused_mod.coverage
new file mode 100644
index 000000000..a8fa24ac6
--- /dev/null
+++ b/tests/coverage/unused_mod.coverage
@@ -0,0 +1,14 @@
+$DIR/auxiliary/unused_mod_helper.rs:
+ LL| |#[allow(dead_code)]
+ LL| 0|pub fn never_called_function() {
+ LL| 0| println!("I am never called");
+ LL| 0|}
+
+$DIR/unused_mod.rs:
+ LL| |#[path = "auxiliary/unused_mod_helper.rs"]
+ LL| |mod unused_module;
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| println!("hello world!");
+ LL| 1|}
+
diff --git a/tests/coverage/unused_mod.rs b/tests/coverage/unused_mod.rs
new file mode 100644
index 000000000..6e62839c9
--- /dev/null
+++ b/tests/coverage/unused_mod.rs
@@ -0,0 +1,6 @@
+#[path = "auxiliary/unused_mod_helper.rs"]
+mod unused_module;
+
+fn main() {
+ println!("hello world!");
+}
diff --git a/tests/coverage/uses_crate.cov-map b/tests/coverage/uses_crate.cov-map
new file mode 100644
index 000000000..9c06eab70
--- /dev/null
+++ b/tests/coverage/uses_crate.cov-map
@@ -0,0 +1,40 @@
+Function name: used_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 27, 1) to (start + 2, 2)
+
+Function name: used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2)
+
+Function name: used_crate::used_only_from_bin_crate_generic_function::<&str>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2)
+
+Function name: used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 1f, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 2)
+
+Function name: uses_crate::main
+Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 07, 02]
+Number of files: 1
+- file 0 => global file 2
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 12, 1) to (start + 7, 2)
+
diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage
new file mode 100644
index 000000000..50d92102a
--- /dev/null
+++ b/tests/coverage/uses_crate.coverage
@@ -0,0 +1,173 @@
+$DIR/auxiliary/used_crate.rs:
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |// Verify that coverage works with optimizations:
+ LL| |// compile-flags: -C opt-level=3
+ LL| |
+ LL| |use std::fmt::Debug;
+ LL| |
+ LL| 1|pub fn used_function() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1| let mut countdown = 0;
+ LL| 1| if is_true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| 1| use_this_lib_crate();
+ LL| 1|}
+ LL| |
+ LL| 2|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+ LL| 2|}
+ ------------------
+ | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
+ ------------------
+ | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+ | LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ | used_crate::used_only_from_bin_crate_generic_function::<&str>:
+ | LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ LL| |// Expect for above function: `Unexecuted instantiation` (see below)
+ LL| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+ LL| 2|}
+ ------------------
+ | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+ | LL| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+ | LL| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ LL| |
+ LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ LL| 2|}
+ ------------------
+ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
+ | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+ | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ LL| |
+ LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ LL| 2|}
+ ------------------
+ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
+ | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
+ | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ LL| |
+ LL| 0|pub fn unused_generic_function<T: Debug>(arg: T) {
+ LL| 0| println!("unused_generic_function with {:?}", arg);
+ LL| 0|}
+ LL| |
+ LL| 0|pub fn unused_function() {
+ LL| 0| let is_true = std::env::args().len() == 1;
+ LL| 0| let mut countdown = 2;
+ LL| 0| if !is_true {
+ LL| 0| countdown = 20;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| |#[allow(dead_code)]
+ LL| 0|fn unused_private_function() {
+ LL| 0| let is_true = std::env::args().len() == 1;
+ LL| 0| let mut countdown = 2;
+ LL| 0| if !is_true {
+ LL| 0| countdown = 20;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| 1|fn use_this_lib_crate() {
+ LL| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs");
+ LL| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
+ LL| 1| "used from library used_crate.rs",
+ LL| 1| );
+ LL| 1| let some_vec = vec![5, 6, 7, 8];
+ LL| 1| used_only_from_this_lib_crate_generic_function(some_vec);
+ LL| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs");
+ LL| 1|}
+ LL| |
+ LL| |// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results,
+ LL| |// for example:
+ LL| |//
+ LL| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
+ LL| |//
+ LL| |// These notices appear when `llvm-cov` shows instantiations. This may be a
+ LL| |// default option, but it can be suppressed with:
+ LL| |//
+ LL| |// ```shell
+ LL| |// $ `llvm-cov show --show-instantiations=0 ...`
+ LL| |// ```
+ LL| |//
+ LL| |// The notice is triggered because the function is unused by the library itself,
+ LL| |// and when the library is compiled, a synthetic function is generated, so
+ LL| |// unused function coverage can be reported. Coverage can be skipped for unused
+ LL| |// generic functions with:
+ LL| |//
+ LL| |// ```shell
+ LL| |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...`
+ LL| |// ```
+ LL| |//
+ LL| |// Even though this function is used by `uses_crate.rs` (and
+ LL| |// counted), with substitutions for `T`, those instantiations are only generated
+ LL| |// when the generic function is actually used (from the binary, not from this
+ LL| |// library crate). So the test result shows coverage for all instantiated
+ LL| |// versions and their generic type substitutions, plus the `Unexecuted
+ LL| |// instantiation` message for the non-substituted version. This is valid, but
+ LL| |// unfortunately a little confusing.
+ LL| |//
+ LL| |// The library crate has its own coverage map, and the only way to show unused
+ LL| |// coverage of a generic function is to include the generic function in the
+ LL| |// coverage map, marked as an "unused function". If the library were used by
+ LL| |// another binary that never used this generic function, then it would be valid
+ LL| |// to show the unused generic, with unknown substitution (`_`).
+ LL| |//
+ LL| |// The alternative is to exclude all generics from being included in the "unused
+ LL| |// functions" list, which would then omit coverage results for
+ LL| |// `unused_generic_function<T>()`, below.
+
+$DIR/uses_crate.rs:
+ LL| |// This test was failing on Linux for a while due to #110393 somehow making
+ LL| |// the unused functions not instrumented, but it seems to be fine now.
+ LL| |
+ LL| |// Validates coverage now works with optimizations
+ LL| |// compile-flags: -C opt-level=3
+ LL| |
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| |// aux-build:used_crate.rs
+ LL| |extern crate used_crate;
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| used_crate::used_function();
+ LL| 1| let some_vec = vec![1, 2, 3, 4];
+ LL| 1| used_crate::used_only_from_bin_crate_generic_function(&some_vec);
+ LL| 1| used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs");
+ LL| 1| used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec);
+ LL| 1| used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?");
+ LL| 1|}
+
diff --git a/tests/coverage/uses_crate.rs b/tests/coverage/uses_crate.rs
new file mode 100644
index 000000000..ab203ad78
--- /dev/null
+++ b/tests/coverage/uses_crate.rs
@@ -0,0 +1,19 @@
+// This test was failing on Linux for a while due to #110393 somehow making
+// the unused functions not instrumented, but it seems to be fine now.
+
+// Validates coverage now works with optimizations
+// compile-flags: -C opt-level=3
+
+#![allow(unused_assignments, unused_variables)]
+
+// aux-build:used_crate.rs
+extern crate used_crate;
+
+fn main() {
+ used_crate::used_function();
+ let some_vec = vec![1, 2, 3, 4];
+ used_crate::used_only_from_bin_crate_generic_function(&some_vec);
+ used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs");
+ used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec);
+ used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?");
+}
diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map
new file mode 100644
index 000000000..6b621825c
--- /dev/null
+++ b/tests/coverage/uses_inline_crate.cov-map
@@ -0,0 +1,55 @@
+Function name: used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 44, 1) to (start + 2, 2)
+
+Function name: used_inline_crate::used_inline_function
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 01, 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)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 20, 1) to (start + 6, 15)
+- Code(Counter(1)) at (prev + 6, 16) to (start + 2, 6)
+- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
+ = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 1, 2)
+ = (c1 + (c0 - c1))
+
+Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2)
+
+Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&str>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2)
+
+Function name: used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 02, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 49, 1) to (start + 2, 2)
+
+Function name: uses_inline_crate::main
+Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 0a, 02]
+Number of files: 1
+- file 0 => global file 2
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 12, 1) to (start + 10, 2)
+
diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/uses_inline_crate.coverage
new file mode 100644
index 000000000..cc0e01ffd
--- /dev/null
+++ b/tests/coverage/uses_inline_crate.coverage
@@ -0,0 +1,159 @@
+$DIR/auxiliary/used_inline_crate.rs:
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |// Verify that coverage works with optimizations:
+ LL| |// compile-flags: -C opt-level=3
+ LL| |
+ LL| |use std::fmt::Debug;
+ LL| |
+ LL| 1|pub fn used_function() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1| let mut countdown = 0;
+ LL| 1| if is_true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| 1| use_this_lib_crate();
+ LL| 1|}
+ LL| |
+ LL| |#[inline(always)]
+ LL| 1|pub fn used_inline_function() {
+ LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ LL| 1| // dependent conditions.
+ LL| 1| let is_true = std::env::args().len() == 1;
+ LL| 1| let mut countdown = 0;
+ LL| 1| if is_true {
+ LL| 1| countdown = 10;
+ LL| 1| }
+ ^0
+ LL| 1| use_this_lib_crate();
+ LL| 1|}
+ LL| |
+ LL| |#[inline(always)]
+ LL| 2|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+ LL| 2|}
+ ------------------
+ | Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_>
+ ------------------
+ | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+ | LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>:
+ | LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ LL| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
+ LL| |
+ LL| |#[inline(always)]
+ LL| 4|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ LL| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+ LL| 4|}
+ ------------------
+ | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+ | LL| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+ | LL| 2|}
+ ------------------
+ | used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+ | LL| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
+ | LL| 2|}
+ ------------------
+ LL| |
+ LL| |#[inline(always)]
+ LL| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ LL| 3|}
+ ------------------
+ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
+ | LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 2|}
+ ------------------
+ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+ | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ LL| |
+ LL| |#[inline(always)]
+ LL| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ LL| 3|}
+ ------------------
+ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
+ | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 1|}
+ ------------------
+ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
+ | LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
+ | LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
+ | LL| 2|}
+ ------------------
+ LL| |
+ LL| |#[inline(always)]
+ LL| 0|pub fn unused_generic_function<T: Debug>(arg: T) {
+ LL| 0| println!("unused_generic_function with {:?}", arg);
+ LL| 0|}
+ LL| |
+ LL| |#[inline(always)]
+ LL| 0|pub fn unused_function() {
+ LL| 0| let is_true = std::env::args().len() == 1;
+ LL| 0| let mut countdown = 2;
+ LL| 0| if !is_true {
+ LL| 0| countdown = 20;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| |#[inline(always)]
+ LL| |#[allow(dead_code)]
+ LL| 0|fn unused_private_function() {
+ LL| 0| let is_true = std::env::args().len() == 1;
+ LL| 0| let mut countdown = 2;
+ LL| 0| if !is_true {
+ LL| 0| countdown = 20;
+ LL| 0| }
+ LL| 0|}
+ LL| |
+ LL| 2|fn use_this_lib_crate() {
+ LL| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs");
+ LL| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
+ LL| 2| "used from library used_crate.rs",
+ LL| 2| );
+ LL| 2| let some_vec = vec![5, 6, 7, 8];
+ LL| 2| used_only_from_this_lib_crate_generic_function(some_vec);
+ LL| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs");
+ LL| 2|}
+
+$DIR/uses_inline_crate.rs:
+ LL| |// This test was failing on Linux for a while due to #110393 somehow making
+ LL| |// the unused functions not instrumented, but it seems to be fine now.
+ LL| |
+ LL| |// Validates coverage now works with optimizations
+ LL| |// compile-flags: -C opt-level=3
+ LL| |
+ LL| |#![allow(unused_assignments, unused_variables)]
+ LL| |
+ LL| |// aux-build:used_inline_crate.rs
+ LL| |extern crate used_inline_crate;
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| used_inline_crate::used_function();
+ LL| 1| used_inline_crate::used_inline_function();
+ LL| 1| let some_vec = vec![1, 2, 3, 4];
+ LL| 1| used_inline_crate::used_only_from_bin_crate_generic_function(&some_vec);
+ LL| 1| used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs");
+ LL| 1| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec);
+ LL| 1| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
+ LL| 1| "interesting?",
+ LL| 1| );
+ LL| 1|}
+
diff --git a/tests/coverage/uses_inline_crate.rs b/tests/coverage/uses_inline_crate.rs
new file mode 100644
index 000000000..d7b4c3c05
--- /dev/null
+++ b/tests/coverage/uses_inline_crate.rs
@@ -0,0 +1,22 @@
+// This test was failing on Linux for a while due to #110393 somehow making
+// the unused functions not instrumented, but it seems to be fine now.
+
+// Validates coverage now works with optimizations
+// compile-flags: -C opt-level=3
+
+#![allow(unused_assignments, unused_variables)]
+
+// aux-build:used_inline_crate.rs
+extern crate used_inline_crate;
+
+fn main() {
+ used_inline_crate::used_function();
+ used_inline_crate::used_inline_function();
+ let some_vec = vec![1, 2, 3, 4];
+ used_inline_crate::used_only_from_bin_crate_generic_function(&some_vec);
+ used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs");
+ used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec);
+ used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function(
+ "interesting?",
+ );
+}
diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map
new file mode 100644
index 000000000..af250f3fb
--- /dev/null
+++ b/tests/coverage/while.cov-map
@@ -0,0 +1,15 @@
+Function name: while::main
+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 = 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 + Zero)
+- Code(Zero) at (prev + 0, 21) to (start + 1, 6)
+- Code(Expression(1, Sub)) at (prev + 2, 1) to (start + 0, 2)
+ = ((c0 + Zero) - Zero)
+
diff --git a/tests/coverage/while.coverage b/tests/coverage/while.coverage
new file mode 100644
index 000000000..c9d497651
--- /dev/null
+++ b/tests/coverage/while.coverage
@@ -0,0 +1,6 @@
+ LL| 1|fn main() {
+ LL| 1| let num = 9;
+ LL| 1| while num >= 10 {
+ LL| 0| }
+ LL| 1|}
+
diff --git a/tests/coverage/while.rs b/tests/coverage/while.rs
new file mode 100644
index 000000000..781b90b35
--- /dev/null
+++ b/tests/coverage/while.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let num = 9;
+ while num >= 10 {
+ }
+}
diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map
new file mode 100644
index 000000000..369ebe891
--- /dev/null
+++ b/tests/coverage/while_early_ret.cov-map
@@ -0,0 +1,26 @@
+Function name: while_early_ret::main
+Raw bytes (61): 0x[01, 01, 06, 01, 05, 03, 09, 0e, 05, 03, 09, 17, 09, 0d, 11, 09, 01, 04, 01, 01, 1b, 03, 03, 09, 02, 0a, 0e, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 11, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 13, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 6
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 2 operands: lhs = Expression(3, Sub), rhs = Counter(1)
+- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2)
+- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(2)
+- expression 5 operands: lhs = Counter(3), rhs = Counter(4)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 27)
+- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 2, 10)
+ = (c0 + c1)
+- Code(Expression(3, Sub)) at (prev + 5, 13) to (start + 2, 14)
+ = ((c0 + c1) - c2)
+- Code(Expression(2, Sub)) at (prev + 6, 21) to (start + 2, 22)
+ = (((c0 + c1) - c2) - c1)
+- Code(Counter(3)) at (prev + 4, 21) to (start + 0, 27)
+- Code(Counter(4)) at (prev + 4, 21) to (start + 0, 27)
+- Code(Counter(1)) at (prev + 3, 10) to (start + 3, 10)
+- Code(Counter(2)) at (prev + 6, 5) to (start + 0, 11)
+- Code(Expression(4, Add)) at (prev + 1, 1) to (start + 0, 2)
+ = ((c3 + c4) + c2)
+
diff --git a/tests/coverage/while_early_ret.coverage b/tests/coverage/while_early_ret.coverage
new file mode 100644
index 000000000..49d39d366
--- /dev/null
+++ b/tests/coverage/while_early_ret.coverage
@@ -0,0 +1,43 @@
+ LL| |#![allow(unused_assignments)]
+ LL| |// failure-status: 1
+ LL| |
+ LL| 1|fn main() -> Result<(), u8> {
+ LL| 1| let mut countdown = 10;
+ LL| | while
+ LL| 7| countdown
+ LL| 7| >
+ LL| 7| 0
+ LL| | {
+ LL| | if
+ LL| 7| countdown
+ LL| 7| <
+ LL| 7| 5
+ LL| | {
+ LL| | return
+ LL| | if
+ LL| 1| countdown
+ LL| 1| >
+ LL| 1| 8
+ LL| | {
+ LL| 0| Ok(())
+ LL| | }
+ LL| | else
+ LL| | {
+ LL| 1| Err(1)
+ LL| | }
+ LL| | ;
+ LL| 6| }
+ LL| 6| countdown
+ LL| 6| -=
+ LL| 6| 1
+ LL| | ;
+ LL| | }
+ LL| 0| Ok(())
+ LL| 1|}
+ LL| |
+ LL| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and
+ LL| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux
+ LL| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program
+ LL| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical
+ LL| |// to the coverage test for early returns, but this is a limitation that should be fixed.
+
diff --git a/tests/coverage/while_early_ret.rs b/tests/coverage/while_early_ret.rs
new file mode 100644
index 000000000..b2f0eee2c
--- /dev/null
+++ b/tests/coverage/while_early_ret.rs
@@ -0,0 +1,42 @@
+#![allow(unused_assignments)]
+// failure-status: 1
+
+fn main() -> Result<(), u8> {
+ let mut countdown = 10;
+ while
+ countdown
+ >
+ 0
+ {
+ if
+ countdown
+ <
+ 5
+ {
+ return
+ if
+ countdown
+ >
+ 8
+ {
+ Ok(())
+ }
+ else
+ {
+ Err(1)
+ }
+ ;
+ }
+ countdown
+ -=
+ 1
+ ;
+ }
+ Ok(())
+}
+
+// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and
+// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux
+// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program
+// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical
+// to the coverage test for early returns, but this is a limitation that should be fixed.
diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map
new file mode 100644
index 000000000..c9c9709fa
--- /dev/null
+++ b/tests/coverage/yield.cov-map
@@ -0,0 +1,62 @@
+Function name: yield::main
+Raw bytes (106): 0x[01, 01, 0b, 05, 09, 0d, 11, 22, 15, 0d, 11, 11, 15, 22, 15, 0d, 11, 22, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 06, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 22, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 13, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 07, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 11
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 2 operands: lhs = Expression(8, Sub), rhs = Counter(5)
+- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 5 operands: lhs = Expression(8, Sub), rhs = Counter(5)
+- expression 6 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(5)
+- expression 8 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 9 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 10 operands: lhs = Counter(9), rhs = Counter(10)
+Number of file 0 mappings: 16
+- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22)
+- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 46)
+- Code(Counter(3)) at (prev + 1, 39) to (start + 0, 41)
+- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 52)
+ = (c1 + c2)
+- Code(Counter(3)) at (prev + 2, 11) to (start + 0, 46)
+- Code(Expression(8, Sub)) at (prev + 1, 34) to (start + 0, 39)
+ = (c3 - c4)
+- Code(Expression(7, Sub)) at (prev + 0, 44) to (start + 0, 46)
+ = ((c3 - c4) - c5)
+- Code(Expression(4, Add)) at (prev + 1, 14) to (start + 0, 52)
+ = (c4 + c5)
+- Code(Expression(7, Sub)) at (prev + 3, 9) to (start + 0, 22)
+ = ((c3 - c4) - c5)
+- Code(Expression(7, Sub)) at (prev + 7, 11) to (start + 0, 46)
+ = ((c3 - c4) - c5)
+- Code(Counter(8)) at (prev + 1, 39) to (start + 0, 41)
+- Code(Expression(9, Add)) at (prev + 1, 14) to (start + 0, 52)
+ = (c6 + c7)
+- Code(Counter(8)) at (prev + 2, 11) to (start + 0, 46)
+- Code(Counter(11)) at (prev + 1, 39) to (start + 0, 41)
+- Code(Expression(10, Add)) at (prev + 1, 14) to (start + 0, 52)
+ = (c9 + c10)
+- Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2)
+
+Function name: yield::main::{closure#0}
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 1c, 01, 10, 05, 02, 10, 01, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 8, 28) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6)
+
+Function name: yield::main::{closure#1}
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 1c, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16)
+- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16)
+- Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6)
+
diff --git a/tests/coverage/yield.coverage b/tests/coverage/yield.coverage
new file mode 100644
index 000000000..d7e455f21
--- /dev/null
+++ b/tests/coverage/yield.coverage
@@ -0,0 +1,38 @@
+ LL| |#![feature(coroutines, coroutine_trait)]
+ LL| |#![allow(unused_assignments)]
+ LL| |
+ LL| |use std::ops::{Coroutine, CoroutineState};
+ LL| |use std::pin::Pin;
+ LL| |
+ LL| 1|fn main() {
+ LL| 1| let mut coroutine = || {
+ LL| 1| yield 1;
+ LL| 1| return "foo";
+ LL| 1| };
+ LL| |
+ LL| 1| match Pin::new(&mut coroutine).resume(()) {
+ LL| 1| CoroutineState::Yielded(1) => {}
+ LL| 0| _ => panic!("unexpected value from resume"),
+ LL| | }
+ LL| 1| match Pin::new(&mut coroutine).resume(()) {
+ LL| 1| CoroutineState::Complete("foo") => {}
+ LL| 0| _ => panic!("unexpected value from resume"),
+ LL| | }
+ LL| |
+ LL| 1| let mut coroutine = || {
+ LL| 1| yield 1;
+ LL| 1| yield 2;
+ LL| 0| yield 3;
+ LL| 0| return "foo";
+ LL| 0| };
+ LL| |
+ LL| 1| match Pin::new(&mut coroutine).resume(()) {
+ LL| 1| CoroutineState::Yielded(1) => {}
+ LL| 0| _ => panic!("unexpected value from resume"),
+ LL| | }
+ LL| 1| match Pin::new(&mut coroutine).resume(()) {
+ LL| 1| CoroutineState::Yielded(2) => {}
+ LL| 0| _ => panic!("unexpected value from resume"),
+ LL| | }
+ LL| 1|}
+
diff --git a/tests/coverage/yield.rs b/tests/coverage/yield.rs
new file mode 100644
index 000000000..b7e2ba31b
--- /dev/null
+++ b/tests/coverage/yield.rs
@@ -0,0 +1,37 @@
+#![feature(coroutines, coroutine_trait)]
+#![allow(unused_assignments)]
+
+use std::ops::{Coroutine, CoroutineState};
+use std::pin::Pin;
+
+fn main() {
+ let mut coroutine = || {
+ yield 1;
+ return "foo";
+ };
+
+ match Pin::new(&mut coroutine).resume(()) {
+ CoroutineState::Yielded(1) => {}
+ _ => panic!("unexpected value from resume"),
+ }
+ match Pin::new(&mut coroutine).resume(()) {
+ CoroutineState::Complete("foo") => {}
+ _ => panic!("unexpected value from resume"),
+ }
+
+ let mut coroutine = || {
+ yield 1;
+ yield 2;
+ yield 3;
+ return "foo";
+ };
+
+ match Pin::new(&mut coroutine).resume(()) {
+ CoroutineState::Yielded(1) => {}
+ _ => panic!("unexpected value from resume"),
+ }
+ match Pin::new(&mut coroutine).resume(()) {
+ CoroutineState::Yielded(2) => {}
+ _ => panic!("unexpected value from resume"),
+ }
+}