about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-07 22:28:51 +0000
committerbors <bors@rust-lang.org>2024-05-07 22:28:51 +0000
commit5486f0c1c2963f095ee4e6e7f69da3a0ad2e4465 (patch)
treebe16aa6a7ac080b6f77f65dcf069e7f68f8607ba
parentfaefc618cf48bd794cbc808448df1bf3f59f36af (diff)
parent7c87ad043098c8d668b25fe09e9b0806d7cb41c5 (diff)
downloadrust-5486f0c1c2963f095ee4e6e7f69da3a0ad2e4465.tar.gz
rust-5486f0c1c2963f095ee4e6e7f69da3a0ad2e4465.zip
Auto merge of #124223 - Zalathar:conditional-let, r=compiler-errors
coverage: Branch coverage support for let-else and if-let

This PR adds branch coverage instrumentation for let-else and if-let, including let-chains.

This lifts two of the limitations listed at #124118.
-rw-r--r--compiler/rustc_mir_build/src/build/coverageinfo.rs26
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs7
-rw-r--r--tests/coverage/branch/if-let.cov-map23
-rw-r--r--tests/coverage/branch/if-let.coverage9
-rw-r--r--tests/coverage/branch/let-else.cov-map9
-rw-r--r--tests/coverage/branch/let-else.coverage3
6 files changed, 64 insertions, 13 deletions
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs
index e2a5f97a847..ee9eeb62990 100644
--- a/compiler/rustc_mir_build/src/build/coverageinfo.rs
+++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs
@@ -1,17 +1,18 @@
-mod mcdc;
 use std::assert_matches::assert_matches;
 use std::collections::hash_map::Entry;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind};
 use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp};
-use rustc_middle::thir::{ExprId, ExprKind, Thir};
+use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::LocalDefId;
 
 use crate::build::coverageinfo::mcdc::MCDCInfoBuilder;
 use crate::build::{Builder, CFG};
 
+mod mcdc;
+
 pub(crate) struct BranchInfoBuilder {
     /// Maps condition expressions to their enclosing `!`, for better instrumentation.
     nots: FxHashMap<ExprId, NotInfo>,
@@ -155,7 +156,7 @@ impl BranchInfoBuilder {
     }
 }
 
-impl Builder<'_, '_> {
+impl<'tcx> Builder<'_, 'tcx> {
     /// If branch coverage is enabled, inject marker statements into `then_block`
     /// and `else_block`, and record their IDs in the table of branch spans.
     pub(crate) fn visit_coverage_branch_condition(
@@ -195,4 +196,23 @@ impl Builder<'_, '_> {
 
         branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
     }
+
+    /// If branch coverage is enabled, inject marker statements into `true_block`
+    /// and `false_block`, and record their IDs in the table of branches.
+    ///
+    /// Used to instrument let-else and if-let (including let-chains) for branch coverage.
+    pub(crate) fn visit_coverage_conditional_let(
+        &mut self,
+        pattern: &Pat<'tcx>, // Pattern that has been matched when the true path is taken
+        true_block: BasicBlock,
+        false_block: BasicBlock,
+    ) {
+        // Bail out if branch coverage is not enabled for this function.
+        let Some(branch_info) = self.coverage_branch_info.as_mut() else { return };
+
+        // FIXME(#124144) This may need special handling when MC/DC is enabled.
+
+        let source_info = SourceInfo { span: pattern.span, scope: self.source_scope };
+        branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
+    }
 }
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 30ebe7d547e..7cf4fac731b 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -2000,6 +2000,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             false,
         );
 
+        // If branch coverage is enabled, record this branch.
+        self.visit_coverage_conditional_let(pat, post_guard_block, otherwise_post_guard_block);
+
         post_guard_block.unit()
     }
 
@@ -2492,6 +2495,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 None,
                 true,
             );
+
+            // If branch coverage is enabled, record this branch.
+            this.visit_coverage_conditional_let(pattern, matching, failure);
+
             this.break_for_else(failure, this.source_info(initializer_span));
             matching.unit()
         });
diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map
index c12df8d9801..0c7d986933e 100644
--- a/tests/coverage/branch/if-let.cov-map
+++ b/tests/coverage/branch/if-let.cov-map
@@ -1,13 +1,16 @@
 Function name: if_let::if_let
-Raw bytes (38): 0x[01, 01, 02, 05, 09, 09, 02, 06, 01, 0c, 01, 01, 10, 02, 03, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 07, 03, 05, 01, 02]
+Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 07, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-Number of file 0 mappings: 6
+Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
-- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 18)
+- Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 12) to (start + 0, 19)
+    true  = (c1 - c2)
+    false = c2
+- Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18)
     = (c1 - c2)
 - Code(Counter(1)) at (prev + 0, 22) to (start + 0, 27)
 - Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 2, 6)
@@ -17,7 +20,7 @@ Number of file 0 mappings: 6
     = (c2 + (c1 - c2))
 
 Function name: if_let::if_let_chain
-Raw bytes (52): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 08, 01, 17, 01, 00, 33, 02, 01, 11, 00, 12, 01, 00, 16, 00, 17, 0d, 01, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02]
+Raw bytes (66): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 0d, 09, 01, 10, 00, 17, 0d, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 4
@@ -25,12 +28,18 @@ Number of expressions: 4
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
 - expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-Number of file 0 mappings: 8
+Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 51)
-- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 18)
+- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 1, 12) to (start + 0, 19)
+    true  = (c0 - c1)
+    false = c1
+- Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18)
     = (c0 - c1)
 - Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23)
-- Code(Counter(3)) at (prev + 1, 21) to (start + 0, 22)
+- Branch { true: Counter(3), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23)
+    true  = c3
+    false = c2
+- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 22)
 - Code(Expression(0, Sub)) at (prev + 0, 26) to (start + 0, 27)
     = (c0 - c1)
 - Code(Counter(3)) at (prev + 1, 5) to (start + 3, 6)
diff --git a/tests/coverage/branch/if-let.coverage b/tests/coverage/branch/if-let.coverage
index f30c5d34eca..9a3f0113f75 100644
--- a/tests/coverage/branch/if-let.coverage
+++ b/tests/coverage/branch/if-let.coverage
@@ -14,6 +14,9 @@
    LL|       |
    LL|      3|    if let Some(x) = input {
                               ^2
+  ------------------
+  |  Branch (LL:12): [True: 2, False: 1]
+  ------------------
    LL|      2|        say(x);
    LL|      2|    } else {
    LL|      1|        say("none");
@@ -24,8 +27,14 @@
    LL|     15|fn if_let_chain(a: Option<&str>, b: Option<&str>) {
    LL|     15|    if let Some(x) = a
                               ^12
+  ------------------
+  |  Branch (LL:12): [True: 12, False: 3]
+  ------------------
    LL|     12|        && let Some(y) = b
                                   ^8
+  ------------------
+  |  Branch (LL:16): [True: 8, False: 4]
+  ------------------
    LL|      8|    {
    LL|      8|        say(x);
    LL|      8|        say(y);
diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map
index ad987bd6bb1..c7f7adddbc2 100644
--- a/tests/coverage/branch/let-else.cov-map
+++ b/tests/coverage/branch/let-else.cov-map
@@ -1,13 +1,16 @@
 Function name: let_else::let_else
-Raw bytes (38): 0x[01, 01, 02, 05, 09, 09, 02, 06, 01, 0c, 01, 01, 10, 02, 03, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 07, 01, 01, 00, 02]
+Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 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(1), rhs = Counter(2)
 - expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-Number of file 0 mappings: 6
+Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
-- Code(Expression(0, Sub)) at (prev + 3, 14) to (start + 0, 15)
+- Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 9) to (start + 0, 16)
+    true  = (c1 - c2)
+    false = c2
+- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 15)
     = (c1 - c2)
 - Code(Counter(1)) at (prev + 0, 19) to (start + 0, 24)
 - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15)
diff --git a/tests/coverage/branch/let-else.coverage b/tests/coverage/branch/let-else.coverage
index 83730e1dfba..22ad8f2b0e1 100644
--- a/tests/coverage/branch/let-else.coverage
+++ b/tests/coverage/branch/let-else.coverage
@@ -14,6 +14,9 @@
    LL|       |
    LL|      3|    let Some(x) = value else {
                            ^2
+  ------------------
+  |  Branch (LL:9): [True: 2, False: 1]
+  ------------------
    LL|      1|        say("none");
    LL|      1|        return;
    LL|       |    };