about summary refs log tree commit diff
diff options
context:
space:
mode:
authorZalathar <Zalathar@users.noreply.github.com>2024-05-01 10:44:31 +1000
committerZalathar <Zalathar@users.noreply.github.com>2024-05-29 20:12:20 +1000
commit34a1828feab6bc634e629849ad73db7042e5c8a5 (patch)
treedc36fe360fdd4f0ff91874d23f0ed4be5f4e1653
parent7845c6e09ca2b9fec6494bbfd5ca3e8af257314b (diff)
downloadrust-34a1828feab6bc634e629849ad73db7042e5c8a5.tar.gz
rust-34a1828feab6bc634e629849ad73db7042e5c8a5.zip
coverage: Add tests for the MC/DC condition limit
-rw-r--r--tests/coverage/mcdc/condition-limit.cov-map162
-rw-r--r--tests/coverage/mcdc/condition-limit.coverage76
-rw-r--r--tests/coverage/mcdc/condition-limit.rs32
-rw-r--r--tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr8
-rw-r--r--tests/ui/instrument-coverage/mcdc-condition-limit.rs32
5 files changed, 310 insertions, 0 deletions
diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map
new file mode 100644
index 00000000000..b4447a33691
--- /dev/null
+++ b/tests/coverage/mcdc/condition-limit.cov-map
@@ -0,0 +1,162 @@
+Function name: condition_limit::bad
+Raw bytes (204): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 11, 01, 14, 01, 03, 09, 20, 05, 02, 03, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 7a, 1d, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 20, 76, 19, 00, 12, 00, 13, 76, 00, 17, 00, 18, 20, 72, 15, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 20, 6e, 11, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 20, 6a, 0d, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 20, 21, 09, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 44
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 3 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 5 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 6 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 7 operands: lhs = Expression(29, Sub), rhs = Counter(5)
+- expression 8 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 9 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 10 operands: lhs = Expression(29, Sub), rhs = Counter(5)
+- expression 11 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 12 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 13 operands: lhs = Expression(28, Sub), rhs = Counter(4)
+- expression 14 operands: lhs = Expression(29, Sub), rhs = Counter(5)
+- expression 15 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 16 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 17 operands: lhs = Expression(28, Sub), rhs = Counter(4)
+- expression 18 operands: lhs = Expression(29, Sub), rhs = Counter(5)
+- expression 19 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 20 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 21 operands: lhs = Expression(27, Sub), rhs = Counter(3)
+- expression 22 operands: lhs = Expression(28, Sub), rhs = Counter(4)
+- expression 23 operands: lhs = Expression(29, Sub), rhs = Counter(5)
+- expression 24 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 25 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 26 operands: lhs = Expression(27, Sub), rhs = Counter(3)
+- expression 27 operands: lhs = Expression(28, Sub), rhs = Counter(4)
+- expression 28 operands: lhs = Expression(29, Sub), rhs = Counter(5)
+- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(6)
+- expression 30 operands: lhs = Counter(1), rhs = Counter(7)
+- expression 31 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub)
+- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(7)
+- expression 33 operands: lhs = Expression(41, Add), rhs = Counter(6)
+- expression 34 operands: lhs = Expression(42, Add), rhs = Counter(5)
+- expression 35 operands: lhs = Expression(43, Add), rhs = Counter(4)
+- expression 36 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 37 operands: lhs = Counter(8), rhs = Expression(38, Add)
+- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub)
+- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(7)
+- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(6)
+- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(5)
+- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4)
+- expression 43 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 17
+- Code(Counter(0)) at (prev + 20, 1) to (start + 3, 9)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 3, 8) to (start + 0, 9)
+    true  = c1
+    false = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Expression(30, Sub), false: Counter(7) } at (prev + 0, 13) to (start + 0, 14)
+    true  = (c1 - c7)
+    false = c7
+- Code(Expression(30, Sub)) at (prev + 0, 18) to (start + 0, 19)
+    = (c1 - c7)
+- Branch { true: Expression(29, Sub), false: Counter(6) } at (prev + 0, 18) to (start + 0, 19)
+    true  = ((c1 - c7) - c6)
+    false = c6
+- Code(Expression(29, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = ((c1 - c7) - c6)
+- Branch { true: Expression(28, Sub), false: Counter(5) } at (prev + 0, 23) to (start + 0, 24)
+    true  = (((c1 - c7) - c6) - c5)
+    false = c5
+- Code(Expression(28, Sub)) at (prev + 0, 28) to (start + 0, 29)
+    = (((c1 - c7) - c6) - c5)
+- Branch { true: Expression(27, Sub), false: Counter(4) } at (prev + 0, 28) to (start + 0, 29)
+    true  = ((((c1 - c7) - c6) - c5) - c4)
+    false = c4
+- Code(Expression(27, Sub)) at (prev + 0, 33) to (start + 0, 34)
+    = ((((c1 - c7) - c6) - c5) - c4)
+- Branch { true: Expression(26, Sub), false: Counter(3) } at (prev + 0, 33) to (start + 0, 34)
+    true  = (((((c1 - c7) - c6) - c5) - c4) - c3)
+    false = c3
+- Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39)
+    = (((((c1 - c7) - c6) - c5) - c4) - c3)
+- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 38) to (start + 0, 39)
+    true  = c8
+    false = c2
+- Code(Counter(8)) at (prev + 0, 40) to (start + 2, 6)
+- Code(Expression(38, Add)) at (prev + 2, 6) to (start + 0, 7)
+    = ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1))
+- Code(Expression(37, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c8 + ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1)))
+
+Function name: condition_limit::good
+Raw bytes (180): 0x[01, 01, 20, 01, 05, 05, 19, 05, 19, 52, 15, 05, 19, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 1d, 6f, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 10, 01, 0c, 01, 03, 09, 28, 00, 06, 03, 08, 00, 22, 30, 05, 02, 01, 06, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 52, 19, 06, 05, 00, 00, 0d, 00, 0e, 52, 00, 12, 00, 13, 30, 4e, 15, 05, 04, 00, 00, 12, 00, 13, 4e, 00, 17, 00, 18, 30, 4a, 11, 04, 03, 00, 00, 17, 00, 18, 4a, 00, 1c, 00, 1d, 30, 46, 0d, 03, 02, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 1d, 09, 02, 00, 00, 00, 21, 00, 22, 1d, 00, 23, 02, 06, 6f, 02, 06, 00, 07, 6b, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 32
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 3 operands: lhs = Expression(20, Sub), rhs = Counter(5)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 5 operands: lhs = Expression(20, Sub), rhs = Counter(5)
+- expression 6 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 7 operands: lhs = Expression(19, Sub), rhs = Counter(4)
+- expression 8 operands: lhs = Expression(20, Sub), rhs = Counter(5)
+- expression 9 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 10 operands: lhs = Expression(19, Sub), rhs = Counter(4)
+- expression 11 operands: lhs = Expression(20, Sub), rhs = Counter(5)
+- expression 12 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(3)
+- expression 14 operands: lhs = Expression(19, Sub), rhs = Counter(4)
+- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(5)
+- expression 16 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(3)
+- expression 18 operands: lhs = Expression(19, Sub), rhs = Counter(4)
+- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(5)
+- expression 20 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 21 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub)
+- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(6)
+- expression 23 operands: lhs = Expression(30, Add), rhs = Counter(5)
+- expression 24 operands: lhs = Expression(31, Add), rhs = Counter(4)
+- expression 25 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 26 operands: lhs = Counter(7), rhs = Expression(27, Add)
+- expression 27 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub)
+- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(6)
+- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(5)
+- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(4)
+- expression 31 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 16
+- Code(Counter(0)) at (prev + 12, 1) to (start + 3, 9)
+- MCDCDecision { bitmap_idx: 0, conditions_num: 6 } at (prev + 3, 8) to (start + 0, 34)
+- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 6, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
+    true  = c1
+    false = (c0 - c1)
+- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Expression(20, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+    true  = (c1 - c6)
+    false = c6
+- Code(Expression(20, Sub)) at (prev + 0, 18) to (start + 0, 19)
+    = (c1 - c6)
+- MCDCBranch { true: Expression(19, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
+    true  = ((c1 - c6) - c5)
+    false = c5
+- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = ((c1 - c6) - c5)
+- MCDCBranch { true: Expression(18, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
+    true  = (((c1 - c6) - c5) - c4)
+    false = c4
+- Code(Expression(18, Sub)) at (prev + 0, 28) to (start + 0, 29)
+    = (((c1 - c6) - c5) - c4)
+- MCDCBranch { true: Expression(17, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29)
+    true  = ((((c1 - c6) - c5) - c4) - c3)
+    false = c3
+- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34)
+    = ((((c1 - c6) - c5) - c4) - c3)
+- MCDCBranch { true: Counter(7), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
+    true  = c7
+    false = c2
+- Code(Counter(7)) at (prev + 0, 35) to (start + 2, 6)
+- Code(Expression(27, Add)) at (prev + 2, 6) to (start + 0, 7)
+    = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))
+- Code(Expression(26, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c7 + (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)))
+
diff --git a/tests/coverage/mcdc/condition-limit.coverage b/tests/coverage/mcdc/condition-limit.coverage
new file mode 100644
index 00000000000..4eb87432fab
--- /dev/null
+++ b/tests/coverage/mcdc/condition-limit.coverage
@@ -0,0 +1,76 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |//@ min-llvm-version: 18
+   LL|       |//@ compile-flags: -Zcoverage-options=mcdc
+   LL|       |//@ llvm-cov-flags: --show-branches=count --show-mcdc
+   LL|       |
+   LL|       |// Check that MC/DC instrumentation can gracefully handle conditions that
+   LL|       |// exceed LLVM's limit of 6 conditions per decision.
+   LL|       |//
+   LL|       |// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.)
+   LL|       |
+   LL|      1|fn good() {
+   LL|      1|    // With only 6 conditions, perform full MC/DC instrumentation.
+   LL|      1|    let [a, b, c, d, e, f] = <[bool; 6]>::default();
+   LL|      1|    if a && b && c && d && e && f {
+                          ^0   ^0   ^0   ^0   ^0
+  ------------------
+  |  Branch (LL:8): [True: 0, False: 1]
+  |  Branch (LL:13): [True: 0, False: 0]
+  |  Branch (LL:18): [True: 0, False: 0]
+  |  Branch (LL:23): [True: 0, False: 0]
+  |  Branch (LL:28): [True: 0, False: 0]
+  |  Branch (LL:33): [True: 0, False: 0]
+  ------------------
+  |---> MC/DC Decision Region (LL:8) to (LL:34)
+  |
+  |  Number of Conditions: 6
+  |     Condition C1 --> (LL:8)
+  |     Condition C2 --> (LL:13)
+  |     Condition C3 --> (LL:18)
+  |     Condition C4 --> (LL:23)
+  |     Condition C5 --> (LL:28)
+  |     Condition C6 --> (LL:33)
+  |
+  |  Executed MC/DC Test Vectors:
+  |
+  |     C1, C2, C3, C4, C5, C6    Result
+  |  1 { F,  -,  -,  -,  -,  -  = F      }
+  |
+  |  C1-Pair: not covered
+  |  C2-Pair: not covered
+  |  C3-Pair: not covered
+  |  C4-Pair: not covered
+  |  C5-Pair: not covered
+  |  C6-Pair: not covered
+  |  MC/DC Coverage for Decision: 0.00%
+  |
+  ------------------
+   LL|      0|        core::hint::black_box("hello");
+   LL|      1|    }
+   LL|      1|}
+   LL|       |
+   LL|      1|fn bad() {
+   LL|      1|    // With 7 conditions, fall back to branch instrumentation only.
+   LL|      1|    let [a, b, c, d, e, f, g] = <[bool; 7]>::default();
+   LL|      1|    if a && b && c && d && e && f && g {
+                          ^0   ^0   ^0   ^0   ^0   ^0
+  ------------------
+  |  Branch (LL:8): [True: 0, False: 1]
+  |  Branch (LL:13): [True: 0, False: 0]
+  |  Branch (LL:18): [True: 0, False: 0]
+  |  Branch (LL:23): [True: 0, False: 0]
+  |  Branch (LL:28): [True: 0, False: 0]
+  |  Branch (LL:33): [True: 0, False: 0]
+  |  Branch (LL:38): [True: 0, False: 0]
+  ------------------
+   LL|      0|        core::hint::black_box("hello");
+   LL|      1|    }
+   LL|      1|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    good();
+   LL|       |    bad();
+   LL|       |}
+
diff --git a/tests/coverage/mcdc/condition-limit.rs b/tests/coverage/mcdc/condition-limit.rs
new file mode 100644
index 00000000000..571c600ebd0
--- /dev/null
+++ b/tests/coverage/mcdc/condition-limit.rs
@@ -0,0 +1,32 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+//@ min-llvm-version: 18
+//@ compile-flags: -Zcoverage-options=mcdc
+//@ llvm-cov-flags: --show-branches=count --show-mcdc
+
+// Check that MC/DC instrumentation can gracefully handle conditions that
+// exceed LLVM's limit of 6 conditions per decision.
+//
+// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.)
+
+fn good() {
+    // With only 6 conditions, perform full MC/DC instrumentation.
+    let [a, b, c, d, e, f] = <[bool; 6]>::default();
+    if a && b && c && d && e && f {
+        core::hint::black_box("hello");
+    }
+}
+
+fn bad() {
+    // With 7 conditions, fall back to branch instrumentation only.
+    let [a, b, c, d, e, f, g] = <[bool; 7]>::default();
+    if a && b && c && d && e && f && g {
+        core::hint::black_box("hello");
+    }
+}
+
+#[coverage(off)]
+fn main() {
+    good();
+    bad();
+}
diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr
new file mode 100644
index 00000000000..4d8d7e1560d
--- /dev/null
+++ b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr
@@ -0,0 +1,8 @@
+warning: Conditions number of the decision (7) exceeds limit (6). MCDC analysis will not count this expression.
+  --> $DIR/mcdc-condition-limit.rs:29:8
+   |
+LL |     if a && b && c && d && e && f && g {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs
new file mode 100644
index 00000000000..64c5f8e9b77
--- /dev/null
+++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs
@@ -0,0 +1,32 @@
+//@ edition: 2021
+//@ min-llvm-version: 18
+//@ revisions: good bad
+//@ check-pass
+//@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime
+
+// Check that we emit some kind of diagnostic when MC/DC instrumentation sees
+// code that exceeds the limit of 6 conditions per decision, and falls back
+// to only instrumenting that code for branch coverage.
+//
+// See also `tests/coverage/mcdc/condition-limit.rs`, which tests the actual
+// effect on instrumentation.
+//
+// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.)
+
+#[cfg(good)]
+fn main() {
+    // 6 conditions is OK, so no diagnostic.
+    let [a, b, c, d, e, f] = <[bool; 6]>::default();
+    if a && b && c && d && e && f {
+        core::hint::black_box("hello");
+    }
+}
+
+#[cfg(bad)]
+fn main() {
+    // 7 conditions is too many, so issue a diagnostic.
+    let [a, b, c, d, e, f, g] = <[bool; 7]>::default();
+    if a && b && c && d && e && f && g { //[bad]~ WARNING Conditions number of the decision
+        core::hint::black_box("hello");
+    }
+}