From fb7e61082fb596fa7f90bf7034d14c77749e4c7f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 21 Apr 2024 18:50:05 +1000 Subject: [PATCH 01/16] coverage: Add another simple test for guarded match arms --- tests/coverage/branch/guard-simple.cov-map | 24 ++++++++++++++++++ tests/coverage/branch/guard-simple.coverage | 28 +++++++++++++++++++++ tests/coverage/branch/guard-simple.rs | 19 ++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 tests/coverage/branch/guard-simple.cov-map create mode 100644 tests/coverage/branch/guard-simple.coverage create mode 100644 tests/coverage/branch/guard-simple.rs diff --git a/tests/coverage/branch/guard-simple.cov-map b/tests/coverage/branch/guard-simple.cov-map new file mode 100644 index 0000000000000..8eb9c54ff4bca --- /dev/null +++ b/tests/coverage/branch/guard-simple.cov-map @@ -0,0 +1,24 @@ +Function name: guard_simple::never_taken +Raw bytes (56): 0x[01, 01, 04, 01, 05, 11, 09, 0f, 0d, 05, 09, 08, 01, 08, 01, 02, 1e, 20, 05, 02, 02, 0e, 00, 1e, 05, 00, 22, 00, 24, 11, 01, 0e, 00, 1e, 20, 09, 06, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 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 = Counter(1) +- expression 1 operands: lhs = Counter(4), 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 +- Code(Counter(0)) at (prev + 8, 1) to (start + 2, 30) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 2, 14) to (start + 0, 30) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 34) to (start + 0, 36) +- Code(Counter(4)) at (prev + 1, 14) to (start + 0, 30) +- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 14) to (start + 0, 30) + true = c2 + false = (c4 - c2) +- Code(Counter(2)) at (prev + 0, 34) to (start + 0, 36) +- Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16) +- Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2) + = ((c1 + c2) + c3) + diff --git a/tests/coverage/branch/guard-simple.coverage b/tests/coverage/branch/guard-simple.coverage new file mode 100644 index 0000000000000..ac90c48c44342 --- /dev/null +++ b/tests/coverage/branch/guard-simple.coverage @@ -0,0 +1,28 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |use core::hint::black_box; + LL| | + LL| 1|fn never_taken() { + LL| 1| match black_box(false) { + LL| 1| _ if black_box(false) => {} + ^0 + ------------------ + | Branch (LL:14): [True: 0, False: 1] + ------------------ + LL| 1| _ if black_box(false) => {} + ^0 + ------------------ + | Branch (LL:14): [True: 0, False: 1] + ------------------ + LL| 1| _ => {} + LL| | } + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | never_taken(); + LL| |} + diff --git a/tests/coverage/branch/guard-simple.rs b/tests/coverage/branch/guard-simple.rs new file mode 100644 index 0000000000000..92fea499cd98d --- /dev/null +++ b/tests/coverage/branch/guard-simple.rs @@ -0,0 +1,19 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch +//@ llvm-cov-flags: --show-branches=count + +use core::hint::black_box; + +fn never_taken() { + match black_box(false) { + _ if black_box(false) => {} + _ if black_box(false) => {} + _ => {} + } +} + +#[coverage(off)] +fn main() { + never_taken(); +} From f2d7e25dc408c1cc893c86208dd727a7d8723c8a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 21 Apr 2024 14:11:14 +1000 Subject: [PATCH 02/16] coverage: Represent branches as a list of arms Within the `InstrumentCoverage` pass, we now represent branches as a list of arms, instead of a true/false pair, until we prepare the final table of mappings to be attached to the MIR body. (We then flatten the list into two-way branches by treating each arm as a branch between its success block, and the total of all later arms.) Currently all of the branches produced by MIR building are still two-way, but this is a step towards allowing many-way branches. --- .../src/coverageinfo/map_data.rs | 21 ++++- .../src/coverage/counters.rs | 7 +- .../src/coverage/mappings.rs | 36 ++++----- .../rustc_mir_transform/src/coverage/mod.rs | 76 +++++++++++++------ 4 files changed, 96 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index 5ed640b840e76..1eec384c68248 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -66,7 +66,14 @@ impl<'tcx> FunctionCoverageCollector<'tcx> { // For each expression ID that is directly used by one or more mappings, // mark it as not-yet-seen. This indicates that we expect to see a // corresponding `ExpressionUsed` statement during MIR traversal. - for mapping in function_coverage_info.mappings.iter() { + for mapping in function_coverage_info + .mappings + .iter() + // For many-armed branches, some branch mappings will have expressions + // that don't correspond to any node in the control-flow graph, so don't + // expect to see `ExpressionUsed` statements for them. + .filter(|m| !matches!(m.kind, MappingKind::Branch { .. })) + { // Currently we only worry about ordinary code mappings. // For branch and MC/DC mappings, expressions might not correspond // to any particular point in the control-flow graph. @@ -196,7 +203,11 @@ impl<'tcx> FunctionCoverage<'tcx> { /// Return the source hash, generated from the HIR node structure, and used to indicate whether /// or not the source code structure changed between different compilations. pub(crate) fn source_hash(&self) -> u64 { - if self.is_used { self.function_coverage_info.function_source_hash } else { 0 } + if self.is_used { + self.function_coverage_info.function_source_hash + } else { + 0 + } } /// Returns an iterator over all filenames used by this function's mappings. @@ -240,7 +251,11 @@ impl<'tcx> FunctionCoverage<'tcx> { } fn counter_for_term(&self, term: CovTerm) -> Counter { - if self.is_zero_term(term) { Counter::ZERO } else { Counter::from_term(term) } + if self.is_zero_term(term) { + Counter::ZERO + } else { + Counter::from_term(term) + } } fn is_zero_term(&self, term: CovTerm) -> bool { diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index ef4031c5c034f..59ecf6fdd6041 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -122,7 +122,12 @@ impl CoverageCounters { self.set_bcb_edge_counter(from_bcb, to_bcb, counter) } - fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter { + pub(super) fn make_expression( + &mut self, + lhs: BcbCounter, + op: Op, + rhs: BcbCounter, + ) -> BcbCounter { let new_expr = BcbExpression { lhs, op, rhs }; *self .expressions_memo diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index ec5ba354805f1..9f4d4ca4753f6 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -22,14 +22,11 @@ pub(super) struct CodeMapping { pub(super) bcb: BasicCoverageBlock, } -/// This is separate from [`MCDCBranch`] to help prepare for larger changes -/// that will be needed for improved branch coverage in the future. -/// (See .) #[derive(Debug)] -pub(super) struct BranchPair { +pub(super) struct BranchArm { pub(super) span: Span, - pub(super) true_bcb: BasicCoverageBlock, - pub(super) false_bcb: BasicCoverageBlock, + pub(super) pre_guard_bcb: BasicCoverageBlock, + pub(super) arm_taken_bcb: BasicCoverageBlock, } /// Associates an MC/DC branch span with condition info besides fields for normal branch. @@ -61,7 +58,7 @@ pub(super) struct ExtractedMappings { /// only public so that other code can still use exhaustive destructuring. pub(super) num_bcbs: usize, pub(super) code_mappings: Vec, - pub(super) branch_pairs: Vec, + pub(super) branch_arm_lists: Vec>, pub(super) mcdc_bitmap_bytes: u32, pub(super) mcdc_branches: Vec, pub(super) mcdc_decisions: Vec, @@ -76,7 +73,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( basic_coverage_blocks: &CoverageGraph, ) -> ExtractedMappings { let mut code_mappings = vec![]; - let mut branch_pairs = vec![]; + let mut branch_arm_lists = vec![]; let mut mcdc_bitmap_bytes = 0; let mut mcdc_branches = vec![]; let mut mcdc_decisions = vec![]; @@ -98,7 +95,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); } - branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); + branch_arm_lists.extend(extract_branch_arm_lists(mir_body, hir_info, basic_coverage_blocks)); extract_mcdc_mappings( mir_body, @@ -112,7 +109,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( ExtractedMappings { num_bcbs: basic_coverage_blocks.num_nodes(), code_mappings, - branch_pairs, + branch_arm_lists, mcdc_bitmap_bytes, mcdc_branches, mcdc_decisions, @@ -125,7 +122,7 @@ impl ExtractedMappings { let Self { num_bcbs, code_mappings, - branch_pairs, + branch_arm_lists, mcdc_bitmap_bytes: _, mcdc_branches, mcdc_decisions, @@ -140,9 +137,11 @@ impl ExtractedMappings { for &CodeMapping { span: _, bcb } in code_mappings { insert(bcb); } - for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs { - insert(true_bcb); - insert(false_bcb); + for &BranchArm { span: _, pre_guard_bcb, arm_taken_bcb } in + branch_arm_lists.iter().flatten() + { + insert(pre_guard_bcb); + insert(arm_taken_bcb); } for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches { insert(true_bcb); @@ -192,16 +191,16 @@ fn resolve_block_markers( } // FIXME: There is currently a lot of redundancy between -// `extract_branch_pairs` and `extract_mcdc_mappings`. This is needed so +// `extract_branch_arm_lists` and `extract_mcdc_mappings`. This is needed so // that they can each be modified without interfering with the other, but in // the long term we should try to bring them together again when branch coverage // and MC/DC coverage support are more mature. -pub(super) fn extract_branch_pairs( +pub(super) fn extract_branch_arm_lists( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Vec { +) -> Vec> { let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return vec![] }; let block_markers = resolve_block_markers(coverage_info_hi, mir_body); @@ -223,7 +222,8 @@ pub(super) fn extract_branch_pairs( let true_bcb = bcb_from_marker(true_marker)?; let false_bcb = bcb_from_marker(false_marker)?; - Some(BranchPair { span, true_bcb, false_bcb }) + let arm = |bcb| BranchArm { span, pre_guard_bcb: bcb, arm_taken_bcb: bcb }; + Some(vec![arm(true_bcb), arm(false_bcb)]) }) .collect::>() } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 104f340c8d63f..ad949c41f97fc 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -13,7 +13,7 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::mir::coverage::{ - CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, SourceRegion, + CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, Op, SourceRegion, }; use rustc_middle::mir::{ self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator, @@ -27,7 +27,7 @@ use tracing::{debug, debug_span, instrument, trace}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; use crate::coverage::graph::CoverageGraph; -use crate::coverage::mappings::ExtractedMappings; +use crate::coverage::mappings::{BranchArm, ExtractedMappings}; /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen @@ -95,10 +95,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: } let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb); - let coverage_counters = + let mut coverage_counters = CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings); - let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters); + let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &mut coverage_counters); if mappings.is_empty() { // No spans could be converted into valid mappings, so skip this function. debug!("no spans could be converted into valid mappings; skipping"); @@ -140,7 +140,7 @@ fn create_mappings<'tcx>( tcx: TyCtxt<'tcx>, hir_info: &ExtractedHirInfo, extracted_mappings: &ExtractedMappings, - coverage_counters: &CoverageCounters, + coverage_counters: &mut CoverageCounters, ) -> Vec { let source_map = tcx.sess.source_map(); let body_span = hir_info.body_span; @@ -153,25 +153,67 @@ fn create_mappings<'tcx>( &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), ); - let term_for_bcb = |bcb| { - coverage_counters - .bcb_counter(bcb) - .expect("all BCBs with spans were given counters") - .as_term() - }; let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span); // Fully destructure the mappings struct to make sure we don't miss any kinds. let ExtractedMappings { num_bcbs: _, code_mappings, - branch_pairs, + branch_arm_lists, mcdc_bitmap_bytes: _, mcdc_branches, mcdc_decisions, } = extracted_mappings; let mut mappings = Vec::new(); + // Process branch arms first, because they might need to mutate `coverage_counters` + // to create new expressions. + for arm_list in branch_arm_lists { + let mut arms_rev = arm_list.iter().rev(); + + let mut rest_counter = { + // The last arm's span is ignored, because its BCB is only used as the + // false branch of the second-last arm; it's not a branch of its own. + let Some(&BranchArm { span: _, pre_guard_bcb, arm_taken_bcb }) = arms_rev.next() else { + continue; + }; + debug_assert_eq!(pre_guard_bcb, arm_taken_bcb, "last arm should not have a guard"); + coverage_counters.bcb_counter(pre_guard_bcb).expect("all relevant BCBs have counters") + }; + + // All relevant BCBs should have counters, so we can `.unwrap()` them. + for &BranchArm { span, pre_guard_bcb, arm_taken_bcb } in arms_rev { + // Number of times the pattern matched. + let matched_counter = coverage_counters.bcb_counter(pre_guard_bcb).unwrap(); + // Number of times the pattern matched and the guard succeeded. + let arm_taken_counter = coverage_counters.bcb_counter(arm_taken_bcb).unwrap(); + // Total number of times execution logically reached this pattern. + let reached_counter = + coverage_counters.make_expression(rest_counter, Op::Add, arm_taken_counter); + // Number of times execution reached this pattern, but didn't match it. + let unmatched_counter = + coverage_counters.make_expression(reached_counter, Op::Subtract, matched_counter); + + let kind = MappingKind::Branch { + true_term: matched_counter.as_term(), + false_term: unmatched_counter.as_term(), + }; + + if let Some(source_region) = region_for_span(span) { + mappings.push(Mapping { kind, source_region }); + } + + rest_counter = reached_counter; + } + } + + let term_for_bcb = |bcb| { + coverage_counters + .bcb_counter(bcb) + .expect("all BCBs with spans were given counters") + .as_term() + }; + mappings.extend(code_mappings.iter().filter_map( // Ordinary code mappings are the simplest kind. |&mappings::CodeMapping { span, bcb }| { @@ -181,16 +223,6 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(branch_pairs.iter().filter_map( - |&mappings::BranchPair { span, true_bcb, false_bcb }| { - let true_term = term_for_bcb(true_bcb); - let false_term = term_for_bcb(false_bcb); - let kind = MappingKind::Branch { true_term, false_term }; - let source_region = region_for_span(span)?; - Some(Mapping { kind, source_region }) - }, - )); - mappings.extend(mcdc_branches.iter().filter_map( |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| { let source_region = region_for_span(span)?; From 413011d245d16300e448245dcb656925072522e3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 21 Apr 2024 14:28:08 +1000 Subject: [PATCH 03/16] coverage: Represent branches as a list of arms during MIR building, too --- compiler/rustc_middle/src/mir/coverage.rs | 12 +++-- compiler/rustc_middle/src/mir/pretty.rs | 24 +++++----- .../rustc_mir_build/src/build/coverageinfo.rs | 38 ++++++++-------- .../src/coverage/mappings.rs | 45 ++++++++++++------- ...rage_cleanup.main.CleanupPostBorrowck.diff | 7 ++- ...erage_cleanup.main.InstrumentCoverage.diff | 7 ++- 6 files changed, 79 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index bfe2a2c2cb3db..27836e802a0d9 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -274,17 +274,21 @@ pub struct CoverageInfoHi { /// injected into the MIR body. This makes it possible to allocate per-ID /// data structures without having to scan the entire body first. pub num_block_markers: usize, - pub branch_spans: Vec, + pub branch_arm_lists: Vec>, pub mcdc_branch_spans: Vec, pub mcdc_decision_spans: Vec, } #[derive(Clone, Debug)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct BranchSpan { +pub struct BranchArm { pub span: Span, - pub true_marker: BlockMarkerId, - pub false_marker: BlockMarkerId, + /// Marks the block that is jumped to after this arm's pattern matches, + /// but before its guard is checked. + pub pre_guard_marker: BlockMarkerId, + /// Marks the block that is jumped to after this arm's guard succeeds. + /// If this is equal to `pre_guard_marker`, the arm has no guard. + pub arm_taken_marker: BlockMarkerId, } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 4878956521831..47b988585391e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -537,7 +537,7 @@ fn write_coverage_info_hi( ) -> io::Result<()> { let coverage::CoverageInfoHi { num_block_markers: _, - branch_spans, + branch_arm_lists, mcdc_branch_spans, mcdc_decision_spans, } = coverage_info_hi; @@ -545,11 +545,12 @@ fn write_coverage_info_hi( // Only add an extra trailing newline if we printed at least one thing. let mut did_print = false; - for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans { - writeln!( - w, - "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", - )?; + for arms in branch_arm_lists { + writeln!(w, "{INDENT}coverage branches {{")?; + for coverage::BranchArm { span, pre_guard_marker, arm_taken_marker } in arms { + writeln!(w, "{INDENT}{INDENT}{pre_guard_marker:?}, {arm_taken_marker:?} => {span:?}")?; + } + writeln!(w, "{INDENT}}}")?; did_print = true; } @@ -1739,12 +1740,13 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( } } else if let Some(prov) = alloc.provenance().get(i, &tcx) { // Memory with provenance must be defined - assert!( - alloc.init_mask().is_range_initialized(alloc_range(i, Size::from_bytes(1))).is_ok() - ); + assert!(alloc + .init_mask() + .is_range_initialized(alloc_range(i, Size::from_bytes(1))) + .is_ok()); ascii.push('━'); // HEAVY HORIZONTAL - // We have two characters to display this, which is obviously not enough. - // Format is similar to "oversized" above. + // We have two characters to display this, which is obviously not enough. + // Format is similar to "oversized" above. let j = i.bytes_usize(); let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0]; write!(w, "╾{c:02x}{prov:#?} (1 ptr byte)╼")?; diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 204ee45bfa2d7..0022d8b40a2af 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -2,7 +2,7 @@ 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, CoverageInfoHi, CoverageKind}; +use rustc_middle::mir::coverage::{BlockMarkerId, BranchArm, CoverageInfoHi, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp}; use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir}; use rustc_middle::ty::TyCtxt; @@ -23,13 +23,14 @@ pub(crate) struct CoverageInfoBuilder { /// Present if branch coverage is enabled. branch_info: Option, + /// Present if MC/DC coverage is enabled. mcdc_info: Option, } #[derive(Default)] struct BranchInfo { - branch_spans: Vec, + branch_arm_lists: Vec>, } #[derive(Clone, Copy)] @@ -141,6 +142,9 @@ impl CoverageInfoBuilder { true_block: BasicBlock, false_block: BasicBlock, ) { + // Bail out if branch coverage is not enabled. + let Some(branch_info) = self.branch_info.as_mut() else { return }; + // Separate path for handling branches when MC/DC is enabled. if let Some(mcdc_info) = self.mcdc_info.as_mut() { let inject_block_marker = @@ -152,29 +156,23 @@ impl CoverageInfoBuilder { false_block, inject_block_marker, ); - return; + } else { + let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); + let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); + + let arm = |marker| BranchArm { + span: source_info.span, + pre_guard_marker: marker, + arm_taken_marker: marker, + }; + branch_info.branch_arm_lists.push(vec![arm(true_marker), arm(false_marker)]); } - - // Bail out if branch coverage is not enabled. - let Some(branch_info) = self.branch_info.as_mut() else { return }; - - let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); - let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); - - branch_info.branch_spans.push(BranchSpan { - span: source_info.span, - true_marker, - false_marker, - }); } pub(crate) fn into_done(self) -> Box { let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } = self; - let branch_spans = - branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default(); - let (mcdc_decision_spans, mcdc_branch_spans) = mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default(); @@ -182,7 +180,7 @@ impl CoverageInfoBuilder { // if there's nothing interesting in it. Box::new(CoverageInfoHi { num_block_markers, - branch_spans, + branch_arm_lists: branch_info.map(|i| i.branch_arm_lists).unwrap_or_default(), mcdc_branch_spans, mcdc_decision_spans, }) @@ -255,7 +253,7 @@ 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. + /// and `else_block`, and record their IDs in the branch table. pub(crate) fn visit_coverage_branch_condition( &mut self, mut expr_id: ExprId, diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 9f4d4ca4753f6..0a376402c1400 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -4,7 +4,7 @@ use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; use rustc_middle::mir::coverage::{ - BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind, + BlockMarkerId, ConditionInfo, CoverageInfoHi, CoverageKind, }; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; @@ -206,24 +206,39 @@ pub(super) fn extract_branch_arm_lists( let block_markers = resolve_block_markers(coverage_info_hi, mir_body); coverage_info_hi - .branch_spans + .branch_arm_lists .iter() - .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| { - // For now, ignore any branch span that was introduced by - // expansion. This makes things like assert macros less noisy. - if !raw_span.ctxt().outer_expn_data().is_root() { - return None; + .filter_map(|arms| { + let mut bcb_arms = Vec::with_capacity(arms.len()); + + // If any arm can't be resolved, return None to skip the entire list + // of arms that contains it. + for &mir::coverage::BranchArm { span: raw_span, pre_guard_marker, arm_taken_marker } in + arms + { + // For now, ignore any branch span that was introduced by + // expansion. This makes things like assert macros less noisy. + if !raw_span.ctxt().outer_expn_data().is_root() { + return None; + } + + let span = unexpand_into_body_span(raw_span, hir_info.body_span)?; + + let pre_guard_bcb = + basic_coverage_blocks.bcb_from_bb(block_markers[pre_guard_marker]?)?; + let arm_taken_bcb = + basic_coverage_blocks.bcb_from_bb(block_markers[arm_taken_marker]?)?; + + bcb_arms.push(BranchArm { span, pre_guard_bcb, arm_taken_bcb }); } - let span = unexpand_into_body_span(raw_span, hir_info.body_span)?; - - let bcb_from_marker = - |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); + assert_eq!(arms.len(), bcb_arms.len()); - let true_bcb = bcb_from_marker(true_marker)?; - let false_bcb = bcb_from_marker(false_marker)?; + if bcb_arms.len() < 2 { + debug_assert!(false, "MIR building shouldn't create branches with <2 arms"); + return None; + } - let arm = |bcb| BranchArm { span, pre_guard_bcb: bcb, arm_taken_bcb: bcb }; - Some(vec![arm(true_bcb), arm(false_bcb)]) + Some(bcb_arms) }) .collect::>() } diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff index efb1559baf5eb..974ef70d5c9cd 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff @@ -5,14 +5,17 @@ let mut _0: (); let mut _1: bool; - coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + coverage branches { + BlockMarkerId(0), BlockMarkerId(0) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + BlockMarkerId(1), BlockMarkerId(1) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + } coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; + coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36; coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39; coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40; coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2; - coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; bb0: { Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff index a0fe9a5c05cd1..f6d7fb296ec03 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff @@ -5,14 +5,17 @@ let mut _0: (); let mut _1: bool; - coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + coverage branches { + BlockMarkerId(0), BlockMarkerId(0) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + BlockMarkerId(1), BlockMarkerId(1) => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + } + coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; ++ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; + coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36; + coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39; + coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40; + coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2; -+ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; + bb0: { + Coverage::CounterIncrement(0); From 50b715782dc92d02f69a63188298c57be4f31b3e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 18 Apr 2024 20:39:02 +1000 Subject: [PATCH 04/16] coverage: Treat each match arm as a "branch" for branch coverage --- .../src/coverageinfo/map_data.rs | 12 +- compiler/rustc_middle/src/mir/pretty.rs | 11 +- .../rustc_mir_build/src/build/coverageinfo.rs | 34 +++++ .../rustc_mir_build/src/build/matches/mod.rs | 24 +++- .../src/coverage/mappings.rs | 4 +- tests/coverage/branch/guard-simple.cov-map | 33 +++-- tests/coverage/branch/guard-simple.coverage | 2 + tests/coverage/branch/guard.cov-map | 46 ++++-- tests/coverage/branch/guard.coverage | 5 + tests/coverage/branch/match-arms.cov-map | 132 ++++++++++++++---- tests/coverage/branch/match-arms.coverage | 15 +- tests/coverage/branch/match-arms.rs | 2 +- ...ch_match_arms.main.InstrumentCoverage.diff | 68 +++++++++ 13 files changed, 308 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index 1eec384c68248..78d481b266289 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -203,11 +203,7 @@ impl<'tcx> FunctionCoverage<'tcx> { /// Return the source hash, generated from the HIR node structure, and used to indicate whether /// or not the source code structure changed between different compilations. pub(crate) fn source_hash(&self) -> u64 { - if self.is_used { - self.function_coverage_info.function_source_hash - } else { - 0 - } + if self.is_used { self.function_coverage_info.function_source_hash } else { 0 } } /// Returns an iterator over all filenames used by this function's mappings. @@ -251,11 +247,7 @@ impl<'tcx> FunctionCoverage<'tcx> { } fn counter_for_term(&self, term: CovTerm) -> Counter { - if self.is_zero_term(term) { - Counter::ZERO - } else { - Counter::from_term(term) - } + if self.is_zero_term(term) { Counter::ZERO } else { Counter::from_term(term) } } fn is_zero_term(&self, term: CovTerm) -> bool { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 47b988585391e..cb0b9e68e9675 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1740,13 +1740,12 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( } } else if let Some(prov) = alloc.provenance().get(i, &tcx) { // Memory with provenance must be defined - assert!(alloc - .init_mask() - .is_range_initialized(alloc_range(i, Size::from_bytes(1))) - .is_ok()); + assert!( + alloc.init_mask().is_range_initialized(alloc_range(i, Size::from_bytes(1))).is_ok() + ); ascii.push('━'); // HEAVY HORIZONTAL - // We have two characters to display this, which is obviously not enough. - // Format is similar to "oversized" above. + // We have two characters to display this, which is obviously not enough. + // Format is similar to "oversized" above. let j = i.bytes_usize(); let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0]; write!(w, "╾{c:02x}{prov:#?} (1 ptr byte)╼")?; diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 0022d8b40a2af..e38349acab69d 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -43,6 +43,12 @@ struct NotInfo { is_flipped: bool, } +pub(crate) struct MatchArm { + pub(crate) source_info: SourceInfo, + pub(crate) pre_binding_block: Option, + pub(crate) arm_block: BasicBlock, +} + #[derive(Default)] struct BlockMarkerGen { num_block_markers: usize, @@ -169,6 +175,34 @@ impl CoverageInfoBuilder { } } + pub(crate) fn add_match_arms(&mut self, cfg: &mut CFG<'_>, arms: &[MatchArm]) { + // Match expressions with 0-1 arms don't have any branches for their arms. + if arms.len() < 2 { + return; + } + + // FIXME(#124118) The current implementation of branch coverage for + // match arms can't handle or-patterns. + if arms.iter().any(|arm| arm.pre_binding_block.is_none()) { + return; + } + + let branch_arms = arms + .iter() + .map(|&MatchArm { source_info, pre_binding_block, arm_block }| { + let pre_guard_marker = + self.markers.inject_block_marker(cfg, source_info, pre_binding_block.unwrap()); + let arm_taken_marker = + self.markers.inject_block_marker(cfg, source_info, arm_block); + BranchArm { span: source_info.span, pre_guard_marker, arm_taken_marker } + }) + .collect::>(); + + if let Some(branch_info) = self.branch_info.as_mut() { + branch_info.branch_arm_lists.push(branch_arms); + } + } + pub(crate) fn into_done(self) -> Box { let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } = self; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 51ead57020556..4de8a7f2e7e91 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -22,7 +22,7 @@ use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; use crate::build::{ - BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, + BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, coverageinfo, }; // helper functions, broken out by category: @@ -416,7 +416,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { where 'tcx: 'pat, { - let arm_end_blocks: Vec = arms + let mut coverage_match_arms = self.coverage_info.is_some().then_some(vec![]); + + let arm_end_blocks: Vec<_> = arms .into_iter() .zip(built_match_tree.branches) .map(|(arm, branch)| { @@ -451,6 +453,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_scrutinee_place, ); + // FIXME: Propagate this info down to codegen + let pre_binding_block = branch.sub_branches[0].otherwise_block; + let arm_block = this.bind_pattern( outer_source_info, branch, @@ -460,6 +465,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { EmitStorageLive::Yes, ); + if let Some(coverage_match_arms) = coverage_match_arms.as_mut() { + coverage_match_arms.push(coverageinfo::MatchArm { + source_info: this.source_info(arm.pattern.span), + pre_binding_block: Some(pre_binding_block), + arm_block, + }) + } + this.fixed_temps_scope = old_dedup_scope; if let Some(source_scope) = scope { @@ -472,6 +485,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .collect(); + if let Some(coverage_match_arms) = coverage_match_arms { + self.coverage_info + .as_mut() + .expect("checked when creating `coverage_match_arms`") + .add_match_arms(&mut self.cfg, &coverage_match_arms); + } + // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 0a376402c1400..946da656d6abd 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -3,9 +3,7 @@ use std::collections::BTreeSet; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; -use rustc_middle::mir::coverage::{ - BlockMarkerId, ConditionInfo, CoverageInfoHi, CoverageKind, -}; +use rustc_middle::mir::coverage::{BlockMarkerId, ConditionInfo, CoverageInfoHi, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; diff --git a/tests/coverage/branch/guard-simple.cov-map b/tests/coverage/branch/guard-simple.cov-map index 8eb9c54ff4bca..50654ae661afb 100644 --- a/tests/coverage/branch/guard-simple.cov-map +++ b/tests/coverage/branch/guard-simple.cov-map @@ -1,24 +1,35 @@ Function name: guard_simple::never_taken -Raw bytes (56): 0x[01, 01, 04, 01, 05, 11, 09, 0f, 0d, 05, 09, 08, 01, 08, 01, 02, 1e, 20, 05, 02, 02, 0e, 00, 1e, 05, 00, 22, 00, 24, 11, 01, 0e, 00, 1e, 20, 09, 06, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] +Raw bytes (80): 0x[01, 01, 09, 07, 01, 17, 05, 0d, 09, 01, 05, 17, 11, 0d, 09, 11, 09, 23, 0d, 05, 09, 0a, 01, 08, 01, 02, 1e, 20, 01, 02, 02, 09, 00, 0a, 20, 05, 0e, 00, 0e, 00, 1e, 05, 00, 22, 00, 24, 20, 11, 12, 01, 09, 00, 0a, 11, 00, 0e, 00, 1e, 20, 09, 1a, 00, 0e, 00, 1e, 09, 00, 22, 00, 24, 0d, 01, 0e, 00, 10, 1f, 02, 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 = Counter(4), 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 expressions: 9 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(0) +- expression 1 operands: lhs = Expression(5, Add), rhs = Counter(1) +- expression 2 operands: lhs = Counter(3), rhs = Counter(2) +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(4) +- expression 5 operands: lhs = Counter(3), rhs = Counter(2) +- expression 6 operands: lhs = Counter(4), rhs = Counter(2) +- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(3) +- expression 8 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 8, 1) to (start + 2, 30) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 2, 14) to (start + 0, 30) +- Branch { true: Counter(0), false: Expression(0, Sub) } at (prev + 2, 9) to (start + 0, 10) + true = c0 + false = (((c3 + c2) + c1) - c0) +- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 14) to (start + 0, 30) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 34) to (start + 0, 36) -- Code(Counter(4)) at (prev + 1, 14) to (start + 0, 30) -- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 14) to (start + 0, 30) +- Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 1, 9) to (start + 0, 10) + true = c4 + false = ((c3 + c2) - c4) +- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 30) +- Branch { true: Counter(2), false: Expression(6, Sub) } at (prev + 0, 14) to (start + 0, 30) true = c2 false = (c4 - c2) - Code(Counter(2)) at (prev + 0, 34) to (start + 0, 36) - Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16) -- Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2) +- Code(Expression(7, Add)) at (prev + 2, 1) to (start + 0, 2) = ((c1 + c2) + c3) diff --git a/tests/coverage/branch/guard-simple.coverage b/tests/coverage/branch/guard-simple.coverage index ac90c48c44342..06ad332a927da 100644 --- a/tests/coverage/branch/guard-simple.coverage +++ b/tests/coverage/branch/guard-simple.coverage @@ -10,11 +10,13 @@ LL| 1| _ if black_box(false) => {} ^0 ------------------ + | Branch (LL:9): [True: 1, False: 0] | Branch (LL:14): [True: 0, False: 1] ------------------ LL| 1| _ if black_box(false) => {} ^0 ------------------ + | Branch (LL:9): [True: 1, False: 0] | Branch (LL:14): [True: 0, False: 1] ------------------ LL| 1| _ => {} diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map index d67c3d349a14e..18dd0c302cbfa 100644 --- a/tests/coverage/branch/guard.cov-map +++ b/tests/coverage/branch/guard.cov-map @@ -1,32 +1,48 @@ Function name: guard::branch_match_guard -Raw bytes (85): 0x[01, 01, 06, 19, 0d, 05, 09, 0f, 15, 13, 11, 17, 0d, 05, 09, 0d, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 17, 03, 0e, 02, 0a, 0b, 04, 01, 00, 02] +Raw bytes (120): 0x[01, 01, 0d, 1b, 0d, 33, 11, 05, 09, 03, 19, 19, 0d, 1b, 1d, 33, 11, 05, 09, 05, 09, 2b, 15, 2f, 11, 33, 0d, 05, 09, 10, 01, 0c, 01, 01, 10, 1d, 03, 0b, 00, 0c, 20, 15, 03, 01, 09, 00, 10, 15, 00, 14, 02, 0a, 20, 19, 0e, 03, 09, 00, 10, 0d, 00, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 12, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 20, 1d, 16, 03, 09, 00, 10, 11, 00, 0e, 00, 0f, 1d, 00, 14, 00, 19, 20, 11, 09, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 33, 03, 0e, 02, 0a, 27, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 -- expression 0 operands: lhs = Counter(6), rhs = Counter(3) -- expression 1 operands: lhs = Counter(1), rhs = Counter(2) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) -- expression 5 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 13 +Number of expressions: 13 +- expression 0 operands: lhs = Expression(6, Add), rhs = Counter(3) +- expression 1 operands: lhs = Expression(12, Add), rhs = Counter(4) +- expression 2 operands: lhs = Counter(1), rhs = Counter(2) +- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(6) +- expression 4 operands: lhs = Counter(6), rhs = Counter(3) +- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(7) +- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(4) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) +- expression 8 operands: lhs = Counter(1), rhs = Counter(2) +- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(5) +- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4) +- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3) +- expression 12 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 16 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) - Code(Counter(7)) at (prev + 3, 11) to (start + 0, 12) -- Code(Counter(5)) at (prev + 1, 20) to (start + 2, 10) -- Code(Counter(3)) at (prev + 3, 14) to (start + 0, 15) +- Branch { true: Counter(5), false: Expression(0, Add) } at (prev + 1, 9) to (start + 0, 16) + true = c5 + false = (((c1 + c2) + c4) + c3) +- Code(Counter(5)) at (prev + 0, 20) to (start + 2, 10) +- Branch { true: Counter(6), false: Expression(3, Sub) } at (prev + 3, 9) to (start + 0, 16) + true = c6 + false = ((((c1 + c2) + c4) + c3) - c6) +- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 15) - Code(Counter(6)) at (prev + 0, 20) to (start + 0, 25) -- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30) +- Branch { true: Counter(3), false: Expression(4, Sub) } at (prev + 0, 20) to (start + 0, 30) true = c3 false = (c6 - c3) - Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10) -- Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15) +- Branch { true: Counter(7), false: Expression(5, Sub) } at (prev + 3, 9) to (start + 0, 16) + true = c7 + false = (((c1 + c2) + c4) - c7) +- Code(Counter(4)) at (prev + 0, 14) to (start + 0, 15) - Code(Counter(7)) at (prev + 0, 20) to (start + 0, 25) - Branch { true: Counter(4), false: Counter(2) } at (prev + 0, 20) to (start + 0, 30) true = c4 false = c2 - Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10) -- Code(Expression(5, Add)) at (prev + 3, 14) to (start + 2, 10) +- Code(Expression(12, Add)) at (prev + 3, 14) to (start + 2, 10) = (c1 + c2) -- Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2) +- Code(Expression(9, Add)) at (prev + 4, 1) to (start + 0, 2) = ((((c1 + c2) + c3) + c4) + c5) diff --git a/tests/coverage/branch/guard.coverage b/tests/coverage/branch/guard.coverage index f89b965b5d0f7..6b1b650d4703c 100644 --- a/tests/coverage/branch/guard.coverage +++ b/tests/coverage/branch/guard.coverage @@ -14,17 +14,22 @@ LL| | LL| 1| match x { LL| 1| Some(0) => { + ------------------ + | Branch (LL:9): [True: 1, False: 3] + ------------------ LL| 1| println!("zero"); LL| 1| } LL| 3| Some(x) if x % 2 == 0 => { ^2 ------------------ + | Branch (LL:9): [True: 3, False: 0] | Branch (LL:20): [True: 2, False: 1] ------------------ LL| 2| println!("is nonzero and even"); LL| 2| } LL| 1| Some(x) if x % 3 == 0 => { ------------------ + | Branch (LL:9): [True: 1, False: 0] | Branch (LL:20): [True: 1, False: 0] ------------------ LL| 1| println!("is nonzero and odd, but divisible by 3"); diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index 1f17f11baaa07..04c39db4c5c31 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -1,60 +1,130 @@ Function name: match_arms::guards -Raw bytes (88): 0x[01, 01, 08, 07, 15, 0b, 11, 0f, 0d, 00, 09, 17, 25, 1b, 21, 1f, 1d, 03, 19, 0c, 01, 30, 01, 01, 10, 29, 03, 0b, 00, 10, 19, 01, 11, 00, 29, 20, 19, 09, 00, 17, 00, 1b, 1d, 01, 11, 00, 29, 20, 1d, 0d, 00, 17, 00, 1b, 21, 01, 11, 00, 29, 20, 21, 11, 00, 17, 00, 1b, 25, 01, 11, 00, 29, 20, 25, 15, 00, 17, 00, 1b, 03, 01, 0e, 00, 18, 13, 03, 05, 01, 02] +Raw bytes (212): 0x[01, 01, 2a, 07, 35, 2b, 19, 4b, 1d, 67, 21, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 2b, 31, 4b, 1d, 67, 21, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 4b, 2d, 67, 21, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 67, 29, 9b, 01, 25, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 8f, 01, 25, 93, 01, 21, 97, 01, 1d, 9b, 01, 19, 9f, 01, 15, a3, 01, 11, a7, 01, 0d, 00, 09, 10, 01, 30, 01, 01, 10, 29, 03, 0b, 00, 10, 20, 35, 02, 01, 09, 00, 13, 19, 00, 11, 00, 29, 20, 19, 09, 00, 17, 00, 1b, 20, 31, 26, 01, 09, 00, 13, 1d, 00, 11, 00, 29, 20, 1d, 0d, 00, 17, 00, 1b, 20, 2d, 46, 01, 09, 00, 13, 21, 00, 11, 00, 29, 20, 21, 11, 00, 17, 00, 1b, 20, 29, 62, 01, 09, 00, 13, 25, 00, 11, 00, 29, 20, 25, 15, 00, 17, 00, 1b, 9b, 01, 01, 0e, 00, 18, 8b, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 8 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(5) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3) -- expression 3 operands: lhs = Zero, rhs = Counter(2) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(9) -- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(8) -- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(7) -- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(6) -Number of file 0 mappings: 12 +Number of expressions: 42 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(13) +- expression 1 operands: lhs = Expression(10, Add), rhs = Counter(6) +- expression 2 operands: lhs = Expression(18, Add), rhs = Counter(7) +- expression 3 operands: lhs = Expression(25, Add), rhs = Counter(8) +- expression 4 operands: lhs = Expression(38, Add), rhs = Counter(9) +- expression 5 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 6 operands: lhs = Expression(40, Add), rhs = Counter(4) +- expression 7 operands: lhs = Expression(41, Add), rhs = Counter(3) +- expression 8 operands: lhs = Zero, rhs = Counter(2) +- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(12) +- expression 10 operands: lhs = Expression(18, Add), rhs = Counter(7) +- expression 11 operands: lhs = Expression(25, Add), rhs = Counter(8) +- expression 12 operands: lhs = Expression(38, Add), rhs = Counter(9) +- expression 13 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 14 operands: lhs = Expression(40, Add), rhs = Counter(4) +- expression 15 operands: lhs = Expression(41, Add), rhs = Counter(3) +- expression 16 operands: lhs = Zero, rhs = Counter(2) +- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(11) +- expression 18 operands: lhs = Expression(25, Add), rhs = Counter(8) +- expression 19 operands: lhs = Expression(38, Add), rhs = Counter(9) +- expression 20 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 21 operands: lhs = Expression(40, Add), rhs = Counter(4) +- expression 22 operands: lhs = Expression(41, Add), rhs = Counter(3) +- expression 23 operands: lhs = Zero, rhs = Counter(2) +- expression 24 operands: lhs = Expression(25, Add), rhs = Counter(10) +- expression 25 operands: lhs = Expression(38, Add), rhs = Counter(9) +- expression 26 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 27 operands: lhs = Expression(40, Add), rhs = Counter(4) +- expression 28 operands: lhs = Expression(41, Add), rhs = Counter(3) +- expression 29 operands: lhs = Zero, rhs = Counter(2) +- expression 30 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 31 operands: lhs = Expression(40, Add), rhs = Counter(4) +- expression 32 operands: lhs = Expression(41, Add), rhs = Counter(3) +- expression 33 operands: lhs = Zero, rhs = Counter(2) +- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(9) +- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(8) +- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(7) +- expression 37 operands: lhs = Expression(38, Add), rhs = Counter(6) +- expression 38 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(4) +- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(3) +- expression 41 operands: lhs = Zero, rhs = Counter(2) +Number of file 0 mappings: 16 - Code(Counter(0)) at (prev + 48, 1) to (start + 1, 16) - Code(Counter(10)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(6)) at (prev + 1, 17) to (start + 0, 41) +- Branch { true: Counter(13), false: Expression(0, Sub) } at (prev + 1, 9) to (start + 0, 19) + true = c13 + false = (((((((((Zero + c2) + c3) + c4) + c5) + c9) + c8) + c7) + c6) - c13) +- Code(Counter(6)) at (prev + 0, 17) to (start + 0, 41) - Branch { true: Counter(6), false: Counter(2) } at (prev + 0, 23) to (start + 0, 27) true = c6 false = c2 -- Code(Counter(7)) at (prev + 1, 17) to (start + 0, 41) +- Branch { true: Counter(12), false: Expression(9, Sub) } at (prev + 1, 9) to (start + 0, 19) + true = c12 + false = ((((((((Zero + c2) + c3) + c4) + c5) + c9) + c8) + c7) - c12) +- Code(Counter(7)) at (prev + 0, 17) to (start + 0, 41) - Branch { true: Counter(7), false: Counter(3) } at (prev + 0, 23) to (start + 0, 27) true = c7 false = c3 -- Code(Counter(8)) at (prev + 1, 17) to (start + 0, 41) +- Branch { true: Counter(11), false: Expression(17, Sub) } at (prev + 1, 9) to (start + 0, 19) + true = c11 + false = (((((((Zero + c2) + c3) + c4) + c5) + c9) + c8) - c11) +- Code(Counter(8)) at (prev + 0, 17) to (start + 0, 41) - Branch { true: Counter(8), false: Counter(4) } at (prev + 0, 23) to (start + 0, 27) true = c8 false = c4 -- Code(Counter(9)) at (prev + 1, 17) to (start + 0, 41) +- Branch { true: Counter(10), false: Expression(24, Sub) } at (prev + 1, 9) to (start + 0, 19) + true = c10 + false = ((((((Zero + c2) + c3) + c4) + c5) + c9) - c10) +- Code(Counter(9)) at (prev + 0, 17) to (start + 0, 41) - Branch { true: Counter(9), false: Counter(5) } at (prev + 0, 23) to (start + 0, 27) true = c9 false = c5 -- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 24) +- Code(Expression(38, Add)) at (prev + 1, 14) to (start + 0, 24) = ((((Zero + c2) + c3) + c4) + c5) -- Code(Expression(4, Add)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(34, Add)) at (prev + 3, 5) to (start + 1, 2) = ((((((((Zero + c2) + c3) + c4) + c5) + c6) + c7) + c8) + c9) Function name: match_arms::match_arms -Raw bytes (51): 0x[01, 01, 06, 05, 07, 0b, 11, 09, 0d, 13, 02, 17, 09, 11, 0d, 07, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 11, 01, 11, 00, 21, 0d, 01, 11, 00, 21, 09, 01, 11, 00, 21, 02, 01, 11, 00, 21, 0f, 03, 05, 01, 02] +Raw bytes (102): 0x[01, 01, 15, 17, 0d, 4a, 09, 05, 4f, 53, 11, 09, 0d, 4a, 09, 05, 4f, 53, 11, 09, 0d, 05, 4f, 53, 11, 09, 0d, 05, 4f, 53, 11, 09, 0d, 43, 4a, 47, 09, 11, 0d, 05, 4f, 53, 11, 09, 0d, 0a, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 20, 11, 03, 01, 09, 00, 13, 11, 00, 11, 00, 21, 20, 0d, 17, 01, 09, 00, 13, 0d, 00, 11, 00, 21, 20, 09, 4a, 01, 09, 00, 13, 09, 00, 11, 00, 21, 4a, 01, 11, 00, 21, 3f, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 -- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4) -- expression 2 operands: lhs = Counter(2), rhs = Counter(3) -- expression 3 operands: lhs = Expression(4, Add), rhs = Expression(0, Sub) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(2) -- expression 5 operands: lhs = Counter(4), rhs = Counter(3) -Number of file 0 mappings: 7 +Number of expressions: 21 +- expression 0 operands: lhs = Expression(5, Add), rhs = Counter(3) +- expression 1 operands: lhs = Expression(18, Sub), rhs = Counter(2) +- expression 2 operands: lhs = Counter(1), rhs = Expression(19, Add) +- expression 3 operands: lhs = Expression(20, Add), rhs = Counter(4) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +- expression 5 operands: lhs = Expression(18, Sub), rhs = Counter(2) +- expression 6 operands: lhs = Counter(1), rhs = Expression(19, Add) +- expression 7 operands: lhs = Expression(20, Add), rhs = Counter(4) +- expression 8 operands: lhs = Counter(2), rhs = Counter(3) +- expression 9 operands: lhs = Counter(1), rhs = Expression(19, Add) +- expression 10 operands: lhs = Expression(20, Add), rhs = Counter(4) +- expression 11 operands: lhs = Counter(2), rhs = Counter(3) +- expression 12 operands: lhs = Counter(1), rhs = Expression(19, Add) +- expression 13 operands: lhs = Expression(20, Add), rhs = Counter(4) +- expression 14 operands: lhs = Counter(2), rhs = Counter(3) +- expression 15 operands: lhs = Expression(16, Add), rhs = Expression(18, Sub) +- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(2) +- expression 17 operands: lhs = Counter(4), rhs = Counter(3) +- expression 18 operands: lhs = Counter(1), rhs = Expression(19, Add) +- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(4) +- expression 20 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 24, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 33) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 33) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 33) -- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 33) +- Branch { true: Counter(4), false: Expression(0, Add) } at (prev + 1, 9) to (start + 0, 19) + true = c4 + false = (((c1 - ((c2 + c3) + c4)) + c2) + c3) +- Code(Counter(4)) at (prev + 0, 17) to (start + 0, 33) +- Branch { true: Counter(3), false: Expression(5, Add) } at (prev + 1, 9) to (start + 0, 19) + true = c3 + false = ((c1 - ((c2 + c3) + c4)) + c2) +- Code(Counter(3)) at (prev + 0, 17) to (start + 0, 33) +- Branch { true: Counter(2), false: Expression(18, Sub) } at (prev + 1, 9) to (start + 0, 19) + true = c2 + false = (c1 - ((c2 + c3) + c4)) +- Code(Counter(2)) at (prev + 0, 17) to (start + 0, 33) +- Code(Expression(18, Sub)) at (prev + 1, 17) to (start + 0, 33) = (c1 - ((c2 + c3) + c4)) -- Code(Expression(3, Add)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(15, Add)) at (prev + 3, 5) to (start + 1, 2) = (((c4 + c3) + c2) + (c1 - ((c2 + c3) + c4))) Function name: match_arms::or_patterns diff --git a/tests/coverage/branch/match-arms.coverage b/tests/coverage/branch/match-arms.coverage index ea8a6f97ab154..c02c86c202e21 100644 --- a/tests/coverage/branch/match-arms.coverage +++ b/tests/coverage/branch/match-arms.coverage @@ -26,8 +26,17 @@ LL| | LL| 15| match value { LL| 8| Enum::D(d) => consume(d), + ------------------ + | Branch (LL:9): [True: 8, False: 7] + ------------------ LL| 4| Enum::C(c) => consume(c), + ------------------ + | Branch (LL:9): [True: 4, False: 3] + ------------------ LL| 2| Enum::B(b) => consume(b), + ------------------ + | Branch (LL:9): [True: 2, False: 1] + ------------------ LL| 1| Enum::A(a) => consume(a), LL| | } LL| | @@ -53,18 +62,22 @@ LL| 3| match value { LL| 8| Enum::D(d) if cond => consume(d), ------------------ + | Branch (LL:9): [True: 24, False: 21] | Branch (LL:23): [True: 8, False: 16] ------------------ LL| 4| Enum::C(c) if cond => consume(c), ------------------ + | Branch (LL:9): [True: 12, False: 25] | Branch (LL:23): [True: 4, False: 8] ------------------ LL| 2| Enum::B(b) if cond => consume(b), ------------------ + | Branch (LL:9): [True: 6, False: 27] | Branch (LL:23): [True: 2, False: 4] ------------------ LL| 1| Enum::A(a) if cond => consume(a), ------------------ + | Branch (LL:9): [True: 3, False: 28] | Branch (LL:23): [True: 1, False: 2] ------------------ LL| 30| _ => consume(0), @@ -101,5 +114,5 @@ LL| | } LL| |} LL| | - LL| |// FIXME(#124118) Actually instrument match arms for branch coverage. + LL| |// FIXME(#124118) Support match expressions with or-patterns. diff --git a/tests/coverage/branch/match-arms.rs b/tests/coverage/branch/match-arms.rs index 63151f59ffe9b..0cc55e2212b72 100644 --- a/tests/coverage/branch/match-arms.rs +++ b/tests/coverage/branch/match-arms.rs @@ -87,4 +87,4 @@ fn main() { } } -// FIXME(#124118) Actually instrument match arms for branch coverage. +// FIXME(#124118) Support match expressions with or-patterns. diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index eeeac70b5b8e7..5f643484ab2af 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -26,12 +26,25 @@ debug a => _9; } + coverage branches { + BlockMarkerId(0), BlockMarkerId(1) => $DIR/branch_match_arms.rs:16:9: 16:19 (#0) + BlockMarkerId(2), BlockMarkerId(3) => $DIR/branch_match_arms.rs:17:9: 17:19 (#0) + BlockMarkerId(4), BlockMarkerId(5) => $DIR/branch_match_arms.rs:18:9: 18:19 (#0) + BlockMarkerId(6), BlockMarkerId(7) => $DIR/branch_match_arms.rs:19:9: 19:19 (#0) + } + + coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) }; + coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) }; + coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) }; + coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) }; + coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) }; + coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) }; ++ coverage ExpressionId(6) => Expression { lhs: Expression(2), op: Add, rhs: Counter(1) }; ++ coverage ExpressionId(7) => Expression { lhs: Expression(6), op: Add, rhs: Counter(2) }; ++ coverage ExpressionId(8) => Expression { lhs: Expression(7), op: Add, rhs: Counter(3) }; ++ coverage Branch { true_term: Counter(1), false_term: Expression(2) } => $DIR/branch_match_arms.rs:18:9 - 18:19; ++ coverage Branch { true_term: Counter(2), false_term: Expression(6) } => $DIR/branch_match_arms.rs:17:9 - 17:19; ++ coverage Branch { true_term: Counter(3), false_term: Expression(7) } => $DIR/branch_match_arms.rs:16:9 - 16:19; + coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21; + coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33; + coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33; @@ -55,17 +68,32 @@ bb2: { + Coverage::CounterIncrement(3); +<<<<<<< HEAD falseEdge -> [real: bb8, imaginary: bb3]; +======= + Coverage::BlockMarker(0); + falseEdge -> [real: bb6, imaginary: bb3]; +>>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } bb3: { + Coverage::CounterIncrement(2); +<<<<<<< HEAD falseEdge -> [real: bb7, imaginary: bb4]; +======= + Coverage::BlockMarker(2); + falseEdge -> [real: bb8, imaginary: bb4]; +>>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } bb4: { + Coverage::CounterIncrement(1); +<<<<<<< HEAD falseEdge -> [real: bb6, imaginary: bb5]; +======= + Coverage::BlockMarker(4); + falseEdge -> [real: bb10, imaginary: bb5]; +>>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } bb5: { @@ -73,16 +101,31 @@ StorageLive(_9); _9 = copy ((_1 as A).0: u32); StorageLive(_10); +<<<<<<< HEAD _10 = copy _9; +======= + _10 = _9; + Coverage::BlockMarker(6); + Coverage::BlockMarker(7); +>>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) _0 = consume(move _10) -> [return: bb12, unwind: bb14]; } bb6: { +<<<<<<< HEAD StorageLive(_7); _7 = copy ((_1 as B).0: u32); StorageLive(_8); _8 = copy _7; _0 = consume(move _8) -> [return: bb11, unwind: bb14]; +======= + StorageLive(_3); + _3 = ((_1 as D).0: u32); + StorageLive(_4); + _4 = _3; + Coverage::BlockMarker(1); + _0 = consume(move _4) -> [return: bb7, unwind: bb14]; +>>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } bb7: { @@ -107,12 +150,37 @@ goto -> bb13; } +<<<<<<< HEAD bb10: { +======= + bb8: { + StorageLive(_5); + _5 = ((_1 as C).0: u32); + StorageLive(_6); + _6 = _5; + Coverage::BlockMarker(3); + _0 = consume(move _6) -> [return: bb9, unwind: bb14]; + } + + bb9: { +>>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) StorageDead(_6); StorageDead(_5); goto -> bb13; } +<<<<<<< HEAD +======= + bb10: { + StorageLive(_7); + _7 = ((_1 as B).0: u32); + StorageLive(_8); + _8 = _7; + Coverage::BlockMarker(5); + _0 = consume(move _8) -> [return: bb11, unwind: bb14]; + } + +>>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) bb11: { StorageDead(_8); StorageDead(_7); From 791e544b616adb29cc858e0a018ce02ceb394765 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Mon, 23 Sep 2024 13:38:37 +0900 Subject: [PATCH 05/16] Added primative support for or-patterns in match arm branch-coverage --- .../rustc_mir_build/src/build/coverageinfo.rs | 40 +++++++++++++------ .../rustc_mir_build/src/build/matches/mod.rs | 33 ++++++++++----- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index e38349acab69d..65923518b5211 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -45,10 +45,16 @@ struct NotInfo { pub(crate) struct MatchArm { pub(crate) source_info: SourceInfo, - pub(crate) pre_binding_block: Option, + pub(crate) sub_branches: Vec, pub(crate) arm_block: BasicBlock, } +#[derive(Debug)] +pub(crate) struct MatchArmSubBranch { + pub(crate) source_info: SourceInfo, + pub(crate) start_block: Option, +} + #[derive(Default)] struct BlockMarkerGen { num_block_markers: usize, @@ -181,26 +187,34 @@ impl CoverageInfoBuilder { return; } - // FIXME(#124118) The current implementation of branch coverage for - // match arms can't handle or-patterns. - if arms.iter().any(|arm| arm.pre_binding_block.is_none()) { + let Some(branch_info) = self.branch_info.as_mut() else { return; - } + }; let branch_arms = arms .iter() - .map(|&MatchArm { source_info, pre_binding_block, arm_block }| { - let pre_guard_marker = - self.markers.inject_block_marker(cfg, source_info, pre_binding_block.unwrap()); + .flat_map(|MatchArm { source_info, sub_branches, arm_block }| { let arm_taken_marker = - self.markers.inject_block_marker(cfg, source_info, arm_block); - BranchArm { span: source_info.span, pre_guard_marker, arm_taken_marker } + self.markers.inject_block_marker(cfg, *source_info, *arm_block); + let branch_arms = sub_branches + .iter() + .filter_map(|sub_branch| { + let Some(block) = sub_branch.start_block else { return None }; + let marker = + self.markers.inject_block_marker(cfg, sub_branch.source_info, block); + Some(BranchArm { + span: sub_branch.source_info.span, + pre_guard_marker: marker, + arm_taken_marker, + }) + }) + .collect::>(); + + branch_arms }) .collect::>(); - if let Some(branch_info) = self.branch_info.as_mut() { - branch_info.branch_arm_lists.push(branch_arms); - } + branch_info.branch_arm_lists.push(branch_arms); } pub(crate) fn into_done(self) -> Box { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4de8a7f2e7e91..1e06ab9b27a77 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -5,6 +5,13 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. +use crate::build::expr::as_place::PlaceBuilder; +use crate::build::scope::DropKind; +use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; +use crate::build::{ + coverageinfo, BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, +}; + use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::{BindingMode, ByRef}; @@ -18,12 +25,6 @@ use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; -use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; -use crate::build::expr::as_place::PlaceBuilder; -use crate::build::scope::DropKind; -use crate::build::{ - BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, coverageinfo, -}; // helper functions, broken out by category: mod match_pair; @@ -453,8 +454,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_scrutinee_place, ); - // FIXME: Propagate this info down to codegen - let pre_binding_block = branch.sub_branches[0].otherwise_block; + let sub_branches: Vec<_> = branch + .sub_branches + .iter() + .map(|b| coverageinfo::MatchArmSubBranch { + source_info: this.source_info(b.span), + start_block: b.start_block, + }) + .collect(); let arm_block = this.bind_pattern( outer_source_info, @@ -468,7 +475,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(coverage_match_arms) = coverage_match_arms.as_mut() { coverage_match_arms.push(coverageinfo::MatchArm { source_info: this.source_info(arm.pattern.span), - pre_binding_block: Some(pre_binding_block), + sub_branches, arm_block, }) } @@ -1391,6 +1398,8 @@ pub(crate) struct ArmHasGuard(pub(crate) bool); #[derive(Debug)] struct MatchTreeSubBranch<'tcx> { span: Span, + /// The first block in this sub branch. + start_block: Option, /// The block that is branched to if the corresponding subpattern matches. success_block: BasicBlock, /// The block to branch to if this arm had a guard and the guard fails. @@ -1441,6 +1450,7 @@ impl<'tcx> MatchTreeSubBranch<'tcx> { debug_assert!(candidate.match_pairs.is_empty()); MatchTreeSubBranch { span: candidate.extra_data.span, + start_block: candidate.false_edge_start_block, success_block: candidate.pre_binding_block.unwrap(), otherwise_block: candidate.otherwise_block.unwrap(), bindings: parent_data @@ -1860,7 +1870,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); for candidate in candidates_to_expand.iter_mut() { if !candidate.subcandidates.is_empty() { - self.merge_trivial_subcandidates(candidate); + // FIXME: Support merging trival candidates in branch coverage instrumentation + if self.coverage_info.is_none() { + self.merge_trivial_subcandidates(candidate); + } self.remove_never_subcandidates(candidate); } } From 5ab184a96015af97d07090329328a3c42f2ca5a7 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Mon, 23 Sep 2024 13:39:55 +0900 Subject: [PATCH 06/16] tidy --- compiler/rustc_mir_build/src/build/matches/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 1e06ab9b27a77..a5aabede9a33f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -25,7 +25,6 @@ use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; - // helper functions, broken out by category: mod match_pair; mod simplify; From ff1825e189195085f015a571deb425677e8901ed Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Mon, 23 Sep 2024 19:08:09 +0900 Subject: [PATCH 07/16] tidy --- compiler/rustc_mir_build/src/build/matches/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a5aabede9a33f..0589e92bf23d9 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -5,13 +5,6 @@ //! This also includes code for pattern bindings in `let` statements and //! function parameters. -use crate::build::expr::as_place::PlaceBuilder; -use crate::build::scope::DropKind; -use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; -use crate::build::{ - coverageinfo, BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, -}; - use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::{BindingMode, ByRef}; @@ -25,6 +18,13 @@ use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; use tracing::{debug, instrument}; +use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; +use crate::build::expr::as_place::PlaceBuilder; +use crate::build::scope::DropKind; +use crate::build::{ + BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode, coverageinfo, +}; + // helper functions, broken out by category: mod match_pair; mod simplify; From 1a0a2c2bd9ff610db160e03266043bf84e4e69d6 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Thu, 26 Sep 2024 23:07:16 +0900 Subject: [PATCH 08/16] Bug fixes for or-patterns in match statement coverage --- .../rustc_mir_build/src/build/coverageinfo.rs | 29 +++++++++---------- .../rustc_mir_build/src/build/matches/mod.rs | 6 +--- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 65923518b5211..f460348f7211f 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -46,13 +46,12 @@ struct NotInfo { pub(crate) struct MatchArm { pub(crate) source_info: SourceInfo, pub(crate) sub_branches: Vec, - pub(crate) arm_block: BasicBlock, } #[derive(Debug)] pub(crate) struct MatchArmSubBranch { pub(crate) source_info: SourceInfo, - pub(crate) start_block: Option, + pub(crate) block: BasicBlock, } #[derive(Default)] @@ -193,24 +192,24 @@ impl CoverageInfoBuilder { let branch_arms = arms .iter() - .flat_map(|MatchArm { source_info, sub_branches, arm_block }| { - let arm_taken_marker = - self.markers.inject_block_marker(cfg, *source_info, *arm_block); - let branch_arms = sub_branches + .flat_map(|MatchArm { source_info, sub_branches }| { + sub_branches .iter() - .filter_map(|sub_branch| { - let Some(block) = sub_branch.start_block else { return None }; - let marker = + .map(|sub_branch| { + let block = sub_branch.block; + + let pre_guard_marker = self.markers.inject_block_marker(cfg, sub_branch.source_info, block); - Some(BranchArm { + let arm_taken_marker = + self.markers.inject_block_marker(cfg, *source_info, block); + + BranchArm { span: sub_branch.source_info.span, - pre_guard_marker: marker, + pre_guard_marker, arm_taken_marker, - }) + } }) - .collect::>(); - - branch_arms + .collect::>() }) .collect::>(); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0589e92bf23d9..70468056fbcfc 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -458,7 +458,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .iter() .map(|b| coverageinfo::MatchArmSubBranch { source_info: this.source_info(b.span), - start_block: b.start_block, + block: b.success_block, }) .collect(); @@ -475,7 +475,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { coverage_match_arms.push(coverageinfo::MatchArm { source_info: this.source_info(arm.pattern.span), sub_branches, - arm_block, }) } @@ -1397,8 +1396,6 @@ pub(crate) struct ArmHasGuard(pub(crate) bool); #[derive(Debug)] struct MatchTreeSubBranch<'tcx> { span: Span, - /// The first block in this sub branch. - start_block: Option, /// The block that is branched to if the corresponding subpattern matches. success_block: BasicBlock, /// The block to branch to if this arm had a guard and the guard fails. @@ -1449,7 +1446,6 @@ impl<'tcx> MatchTreeSubBranch<'tcx> { debug_assert!(candidate.match_pairs.is_empty()); MatchTreeSubBranch { span: candidate.extra_data.span, - start_block: candidate.false_edge_start_block, success_block: candidate.pre_binding_block.unwrap(), otherwise_block: candidate.otherwise_block.unwrap(), bindings: parent_data From 578af766170e96cf0a150049bba1155e5a118b28 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 23 Sep 2024 22:58:50 +0900 Subject: [PATCH 09/16] Reverted test that was incorrectly rebased --- ...ch_match_arms.main.InstrumentCoverage.diff | 104 +++--------------- 1 file changed, 18 insertions(+), 86 deletions(-) diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index 5f643484ab2af..3bd18339ec51f 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -1,6 +1,6 @@ - // MIR for `main` before InstrumentCoverage + // MIR for `main` after InstrumentCoverage - + fn main() -> () { let mut _0: (); let mut _1: Enum; @@ -25,33 +25,20 @@ scope 4 { debug a => _9; } - - coverage branches { - BlockMarkerId(0), BlockMarkerId(1) => $DIR/branch_match_arms.rs:16:9: 16:19 (#0) - BlockMarkerId(2), BlockMarkerId(3) => $DIR/branch_match_arms.rs:17:9: 17:19 (#0) - BlockMarkerId(4), BlockMarkerId(5) => $DIR/branch_match_arms.rs:18:9: 18:19 (#0) - BlockMarkerId(6), BlockMarkerId(7) => $DIR/branch_match_arms.rs:19:9: 19:19 (#0) - } - + + coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) }; + coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) }; + coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) }; + coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) }; + coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) }; + coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) }; -+ coverage ExpressionId(6) => Expression { lhs: Expression(2), op: Add, rhs: Counter(1) }; -+ coverage ExpressionId(7) => Expression { lhs: Expression(6), op: Add, rhs: Counter(2) }; -+ coverage ExpressionId(8) => Expression { lhs: Expression(7), op: Add, rhs: Counter(3) }; -+ coverage Branch { true_term: Counter(1), false_term: Expression(2) } => $DIR/branch_match_arms.rs:18:9 - 18:19; -+ coverage Branch { true_term: Counter(2), false_term: Expression(6) } => $DIR/branch_match_arms.rs:17:9 - 17:19; -+ coverage Branch { true_term: Counter(3), false_term: Expression(7) } => $DIR/branch_match_arms.rs:16:9 - 16:19; + coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21; + coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33; + coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33; + coverage Code(Counter(1)) => $DIR/branch_match_arms.rs:18:17 - 18:33; + coverage Code(Expression(2)) => $DIR/branch_match_arms.rs:19:17 - 19:33; + coverage Code(Expression(5)) => $DIR/branch_match_arms.rs:21:1 - 21:2; -+ ++ bb0: { + Coverage::CounterIncrement(0); StorageLive(_1); @@ -60,74 +47,44 @@ _2 = discriminant(_1); switchInt(move _2) -> [0: bb5, 1: bb4, 2: bb3, 3: bb2, otherwise: bb1]; } - + bb1: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - + bb2: { + Coverage::CounterIncrement(3); -<<<<<<< HEAD falseEdge -> [real: bb8, imaginary: bb3]; -======= - Coverage::BlockMarker(0); - falseEdge -> [real: bb6, imaginary: bb3]; ->>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } - + bb3: { + Coverage::CounterIncrement(2); -<<<<<<< HEAD falseEdge -> [real: bb7, imaginary: bb4]; -======= - Coverage::BlockMarker(2); - falseEdge -> [real: bb8, imaginary: bb4]; ->>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } - + bb4: { + Coverage::CounterIncrement(1); -<<<<<<< HEAD falseEdge -> [real: bb6, imaginary: bb5]; -======= - Coverage::BlockMarker(4); - falseEdge -> [real: bb10, imaginary: bb5]; ->>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } - + bb5: { + Coverage::ExpressionUsed(2); StorageLive(_9); _9 = copy ((_1 as A).0: u32); StorageLive(_10); -<<<<<<< HEAD _10 = copy _9; -======= - _10 = _9; - Coverage::BlockMarker(6); - Coverage::BlockMarker(7); ->>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) _0 = consume(move _10) -> [return: bb12, unwind: bb14]; } - + bb6: { -<<<<<<< HEAD StorageLive(_7); _7 = copy ((_1 as B).0: u32); StorageLive(_8); _8 = copy _7; _0 = consume(move _8) -> [return: bb11, unwind: bb14]; -======= - StorageLive(_3); - _3 = ((_1 as D).0: u32); - StorageLive(_4); - _4 = _3; - Coverage::BlockMarker(1); - _0 = consume(move _4) -> [return: bb7, unwind: bb14]; ->>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) } - + bb7: { StorageLive(_5); _5 = copy ((_1 as C).0: u32); @@ -135,7 +92,7 @@ _6 = copy _5; _0 = consume(move _6) -> [return: bb10, unwind: bb14]; } - + bb8: { StorageLive(_3); _3 = copy ((_1 as D).0: u32); @@ -143,64 +100,39 @@ _4 = copy _3; _0 = consume(move _4) -> [return: bb9, unwind: bb14]; } - + bb9: { StorageDead(_4); StorageDead(_3); goto -> bb13; } - -<<<<<<< HEAD + bb10: { -======= - bb8: { - StorageLive(_5); - _5 = ((_1 as C).0: u32); - StorageLive(_6); - _6 = _5; - Coverage::BlockMarker(3); - _0 = consume(move _6) -> [return: bb9, unwind: bb14]; - } - - bb9: { ->>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) StorageDead(_6); StorageDead(_5); goto -> bb13; } - -<<<<<<< HEAD -======= - bb10: { - StorageLive(_7); - _7 = ((_1 as B).0: u32); - StorageLive(_8); - _8 = _7; - Coverage::BlockMarker(5); - _0 = consume(move _8) -> [return: bb11, unwind: bb14]; - } - ->>>>>>> 59595611af7 (coverage: Treat each match arm as a "branch" for branch coverage) + bb11: { StorageDead(_8); StorageDead(_7); goto -> bb13; } - + bb12: { StorageDead(_10); StorageDead(_9); goto -> bb13; } - + bb13: { + Coverage::ExpressionUsed(5); StorageDead(_1); return; } - + bb14 (cleanup): { resume; } } - + From ad74b3a6be1bab4a76d3ecb7025f8f5329547cdd Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Thu, 26 Sep 2024 23:13:57 +0900 Subject: [PATCH 10/16] Fixed a bug that prevent MCDC coverage from running if branch coverage is not also enabled --- compiler/rustc_mir_build/src/build/coverageinfo.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index f460348f7211f..c18c6dbcdb006 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -153,9 +153,6 @@ impl CoverageInfoBuilder { true_block: BasicBlock, false_block: BasicBlock, ) { - // Bail out if branch coverage is not enabled. - let Some(branch_info) = self.branch_info.as_mut() else { return }; - // Separate path for handling branches when MC/DC is enabled. if let Some(mcdc_info) = self.mcdc_info.as_mut() { let inject_block_marker = @@ -168,6 +165,9 @@ impl CoverageInfoBuilder { inject_block_marker, ); } else { + // Bail out if branch coverage is not enabled. + let Some(branch_info) = self.branch_info.as_mut() else { return }; + let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); From d46e6c55128535e3edd7d1de44d4a94d513a803b Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Sat, 28 Sep 2024 16:16:04 +0900 Subject: [PATCH 11/16] Avoid adding duplicate coverage markers for match guards --- compiler/rustc_mir_build/src/build/coverageinfo.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index c18c6dbcdb006..bdc0b7d572b6b 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -168,6 +168,20 @@ impl CoverageInfoBuilder { // Bail out if branch coverage is not enabled. let Some(branch_info) = self.branch_info.as_mut() else { return }; + + // Avoid duplicates coverage markers. + // When lowering match sub-branches (like or-patterns), `if` guards will + // be added multiple times for each sub-branch + // FIXME: This feels dirty. It would be nice to find a smarter way to avoid duplicate + // coverage markers. + for arms in &branch_info.branch_arm_lists { + for arm in arms { + if arm.span == source_info.span { + return; + } + } + } + let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); From 78a7fe1a131927d8a778cffbc4dd0f4e759ee392 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Sat, 28 Sep 2024 16:16:49 +0900 Subject: [PATCH 12/16] Added match or-pattern branch coverage test --- .../branch/match-or-pattern-simple.cov-map | 25 ++++++++++++++ .../branch/match-or-pattern-simple.coverage | 34 +++++++++++++++++++ .../branch/match-or-pattern-simple.rs | 29 ++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tests/coverage/branch/match-or-pattern-simple.cov-map create mode 100644 tests/coverage/branch/match-or-pattern-simple.coverage create mode 100644 tests/coverage/branch/match-or-pattern-simple.rs diff --git a/tests/coverage/branch/match-or-pattern-simple.cov-map b/tests/coverage/branch/match-or-pattern-simple.cov-map new file mode 100644 index 0000000000000..912b04ddaafa6 --- /dev/null +++ b/tests/coverage/branch/match-or-pattern-simple.cov-map @@ -0,0 +1,25 @@ +Function name: match_or_pattern_simple::foo +Raw bytes (50): 0x[01, 01, 06, 01, 07, 05, 09, 09, 05, 05, 02, 09, 17, 05, 02, 06, 01, 08, 01, 01, 17, 20, 02, 0b, 02, 09, 00, 0a, 20, 05, 09, 00, 0d, 00, 0e, 17, 00, 12, 02, 0a, 09, 03, 0e, 02, 0a, 13, 04, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 6 +- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(2), rhs = Counter(1) +- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Add) +- expression 5 operands: lhs = Counter(1), rhs = Expression(0, Sub) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 23) +- Branch { true: Expression(0, Sub), false: Expression(2, Add) } at (prev + 2, 9) to (start + 0, 10) + true = (c0 - (c1 + c2)) + false = (c2 + c1) +- Branch { true: Counter(1), false: Counter(2) } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = c2 +- Code(Expression(5, Add)) at (prev + 0, 18) to (start + 2, 10) + = (c1 + (c0 - (c1 + c2))) +- Code(Counter(2)) at (prev + 3, 14) to (start + 2, 10) +- Code(Expression(4, Add)) at (prev + 4, 1) to (start + 0, 2) + = (c2 + (c1 + (c0 - (c1 + c2)))) + diff --git a/tests/coverage/branch/match-or-pattern-simple.coverage b/tests/coverage/branch/match-or-pattern-simple.coverage new file mode 100644 index 0000000000000..d80c27f4909d0 --- /dev/null +++ b/tests/coverage/branch/match-or-pattern-simple.coverage @@ -0,0 +1,34 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |use core::hint::black_box; + LL| | + LL| 3|fn foo(a: i32) { + LL| 3| match black_box(a) { + LL| 1| 1 | 2 => { + ------------------ + | Branch (LL:9): [True: 1, False: 2] + | Branch (LL:13): [True: 0, False: 2] + ------------------ + LL| 1| consume(1); + LL| 1| } + LL| 2| _ => { + LL| 2| consume(2); + LL| 2| } + LL| | } + LL| 3|} + LL| | + LL| |#[coverage(off)] + LL| |fn consume(x: T) { + LL| | core::hint::black_box(x); + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | foo(1); + LL| | foo(3); + LL| | foo(4); + LL| |} + diff --git a/tests/coverage/branch/match-or-pattern-simple.rs b/tests/coverage/branch/match-or-pattern-simple.rs new file mode 100644 index 0000000000000..72afb72faaeb5 --- /dev/null +++ b/tests/coverage/branch/match-or-pattern-simple.rs @@ -0,0 +1,29 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch +//@ llvm-cov-flags: --show-branches=count + +use core::hint::black_box; + +fn foo(a: i32) { + match black_box(a) { + 1 | 2 => { + consume(1); + } + _ => { + consume(2); + } + } +} + +#[coverage(off)] +fn consume(x: T) { + core::hint::black_box(x); +} + +#[coverage(off)] +fn main() { + foo(1); + foo(3); + foo(4); +} From d6a25ebf55131a6ce548f24b8ca7fef2a1c980b0 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Sun, 29 Sep 2024 12:50:05 +0900 Subject: [PATCH 13/16] Added smarter match guard branch coverage handling --- .../rustc_mir_build/src/build/coverageinfo.rs | 23 +++++++++++-------- .../rustc_mir_build/src/build/matches/mod.rs | 18 ++++++++++----- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index bdc0b7d572b6b..682f5a05fef5f 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -44,14 +44,14 @@ struct NotInfo { } pub(crate) struct MatchArm { - pub(crate) source_info: SourceInfo, pub(crate) sub_branches: Vec, } #[derive(Debug)] pub(crate) struct MatchArmSubBranch { pub(crate) source_info: SourceInfo, - pub(crate) block: BasicBlock, + pub(crate) pre_binding_block: BasicBlock, + pub(crate) branch_taken_block: BasicBlock, } #[derive(Default)] @@ -168,7 +168,6 @@ impl CoverageInfoBuilder { // Bail out if branch coverage is not enabled. let Some(branch_info) = self.branch_info.as_mut() else { return }; - // Avoid duplicates coverage markers. // When lowering match sub-branches (like or-patterns), `if` guards will // be added multiple times for each sub-branch @@ -206,16 +205,20 @@ impl CoverageInfoBuilder { let branch_arms = arms .iter() - .flat_map(|MatchArm { source_info, sub_branches }| { + .flat_map(|MatchArm { sub_branches }| { sub_branches .iter() .map(|sub_branch| { - let block = sub_branch.block; - - let pre_guard_marker = - self.markers.inject_block_marker(cfg, sub_branch.source_info, block); - let arm_taken_marker = - self.markers.inject_block_marker(cfg, *source_info, block); + let pre_guard_marker = self.markers.inject_block_marker( + cfg, + sub_branch.source_info, + sub_branch.pre_binding_block, + ); + let arm_taken_marker = self.markers.inject_block_marker( + cfg, + sub_branch.source_info, + sub_branch.branch_taken_block, + ); BranchArm { span: sub_branch.source_info.span, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 70468056fbcfc..a72f3d9bc59bd 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -453,12 +453,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_scrutinee_place, ); - let sub_branches: Vec<_> = branch + let mut sub_branches: Vec<_> = branch .sub_branches .iter() .map(|b| coverageinfo::MatchArmSubBranch { source_info: this.source_info(b.span), - block: b.success_block, + pre_binding_block: b.success_block, + branch_taken_block: b.success_block, }) .collect(); @@ -471,11 +472,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { EmitStorageLive::Yes, ); + // If the match arm has a guard, change the branch_taken_block for all of the + // sub-branches to be the guard block. + if arm.guard.is_some() { + for sub_branch in sub_branches.iter_mut() { + sub_branch.branch_taken_block = arm_block; + } + } + if let Some(coverage_match_arms) = coverage_match_arms.as_mut() { - coverage_match_arms.push(coverageinfo::MatchArm { - source_info: this.source_info(arm.pattern.span), - sub_branches, - }) + coverage_match_arms.push(coverageinfo::MatchArm { sub_branches }); } this.fixed_temps_scope = old_dedup_scope; From c0dcdc90e01d3789aaa8cbad690dc9587670c426 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Sun, 29 Sep 2024 13:51:22 +0900 Subject: [PATCH 14/16] blessed match-arm branch coverage test --- tests/coverage/branch/match-arms.cov-map | 64 +++++++++++++++-------- tests/coverage/branch/match-arms.coverage | 7 +++ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index 04c39db4c5c31..0edeea3bd3a1e 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -128,35 +128,57 @@ Number of file 0 mappings: 10 = (((c4 + c3) + c2) + (c1 - ((c2 + c3) + c4))) Function name: match_arms::or_patterns -Raw bytes (75): 0x[01, 01, 0d, 11, 0d, 05, 2f, 33, 11, 09, 0d, 09, 2a, 05, 2f, 33, 11, 09, 0d, 03, 27, 09, 2a, 05, 2f, 33, 11, 09, 0d, 09, 01, 25, 01, 01, 10, 05, 03, 0b, 00, 10, 11, 01, 11, 00, 12, 0d, 00, 1e, 00, 1f, 03, 00, 24, 00, 2e, 09, 01, 11, 00, 12, 2a, 00, 1e, 00, 1f, 27, 00, 24, 00, 2e, 23, 03, 05, 01, 02] +Raw bytes (122): 0x[01, 01, 1a, 17, 0d, 5e, 09, 05, 63, 67, 11, 09, 0d, 5e, 09, 05, 63, 67, 11, 09, 0d, 11, 0d, 05, 63, 67, 11, 09, 0d, 05, 63, 67, 11, 09, 0d, 09, 5e, 05, 63, 67, 11, 09, 0d, 57, 5b, 11, 0d, 09, 5e, 05, 63, 67, 11, 09, 0d, 0c, 01, 25, 01, 01, 10, 05, 03, 0b, 00, 10, 20, 11, 03, 01, 09, 00, 13, 11, 00, 11, 00, 12, 20, 0d, 17, 00, 16, 00, 20, 0d, 00, 1e, 00, 1f, 57, 00, 24, 00, 2e, 20, 09, 5e, 01, 09, 00, 13, 09, 00, 11, 00, 12, 5e, 00, 1e, 00, 1f, 5b, 00, 24, 00, 2e, 53, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 13 -- expression 0 operands: lhs = Counter(4), rhs = Counter(3) -- expression 1 operands: lhs = Counter(1), rhs = Expression(11, Add) -- expression 2 operands: lhs = Expression(12, Add), rhs = Counter(4) -- expression 3 operands: lhs = Counter(2), rhs = Counter(3) -- expression 4 operands: lhs = Counter(2), rhs = Expression(10, Sub) -- expression 5 operands: lhs = Counter(1), rhs = Expression(11, Add) -- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(4) -- expression 7 operands: lhs = Counter(2), rhs = Counter(3) -- expression 8 operands: lhs = Expression(0, Add), rhs = Expression(9, Add) -- expression 9 operands: lhs = Counter(2), rhs = Expression(10, Sub) -- expression 10 operands: lhs = Counter(1), rhs = Expression(11, Add) -- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(4) +Number of expressions: 26 +- expression 0 operands: lhs = Expression(5, Add), rhs = Counter(3) +- expression 1 operands: lhs = Expression(23, Sub), rhs = Counter(2) +- expression 2 operands: lhs = Counter(1), rhs = Expression(24, Add) +- expression 3 operands: lhs = Expression(25, Add), rhs = Counter(4) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +- expression 5 operands: lhs = Expression(23, Sub), rhs = Counter(2) +- expression 6 operands: lhs = Counter(1), rhs = Expression(24, Add) +- expression 7 operands: lhs = Expression(25, Add), rhs = Counter(4) +- expression 8 operands: lhs = Counter(2), rhs = Counter(3) +- expression 9 operands: lhs = Counter(4), rhs = Counter(3) +- expression 10 operands: lhs = Counter(1), rhs = Expression(24, Add) +- expression 11 operands: lhs = Expression(25, Add), rhs = Counter(4) - expression 12 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 9 +- expression 13 operands: lhs = Counter(1), rhs = Expression(24, Add) +- expression 14 operands: lhs = Expression(25, Add), rhs = Counter(4) +- expression 15 operands: lhs = Counter(2), rhs = Counter(3) +- expression 16 operands: lhs = Counter(2), rhs = Expression(23, Sub) +- expression 17 operands: lhs = Counter(1), rhs = Expression(24, Add) +- expression 18 operands: lhs = Expression(25, Add), rhs = Counter(4) +- expression 19 operands: lhs = Counter(2), rhs = Counter(3) +- expression 20 operands: lhs = Expression(21, Add), rhs = Expression(22, Add) +- expression 21 operands: lhs = Counter(4), rhs = Counter(3) +- expression 22 operands: lhs = Counter(2), rhs = Expression(23, Sub) +- expression 23 operands: lhs = Counter(1), rhs = Expression(24, Add) +- expression 24 operands: lhs = Expression(25, Add), rhs = Counter(4) +- expression 25 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 12 - Code(Counter(0)) at (prev + 37, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 18) +- Branch { true: Counter(4), false: Expression(0, Add) } at (prev + 1, 9) to (start + 0, 19) + true = c4 + false = (((c1 - ((c2 + c3) + c4)) + c2) + c3) +- Code(Counter(4)) at (prev + 0, 17) to (start + 0, 18) +- Branch { true: Counter(3), false: Expression(5, Add) } at (prev + 0, 22) to (start + 0, 32) + true = c3 + false = ((c1 - ((c2 + c3) + c4)) + c2) - Code(Counter(3)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 46) +- Code(Expression(21, Add)) at (prev + 0, 36) to (start + 0, 46) = (c4 + c3) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(10, Sub)) at (prev + 0, 30) to (start + 0, 31) +- Branch { true: Counter(2), false: Expression(23, Sub) } at (prev + 1, 9) to (start + 0, 19) + true = c2 + false = (c1 - ((c2 + c3) + c4)) +- Code(Counter(2)) at (prev + 0, 17) to (start + 0, 18) +- Code(Expression(23, Sub)) at (prev + 0, 30) to (start + 0, 31) = (c1 - ((c2 + c3) + c4)) -- Code(Expression(9, Add)) at (prev + 0, 36) to (start + 0, 46) +- Code(Expression(22, Add)) at (prev + 0, 36) to (start + 0, 46) = (c2 + (c1 - ((c2 + c3) + c4))) -- Code(Expression(8, Add)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(20, Add)) at (prev + 3, 5) to (start + 1, 2) = ((c4 + c3) + (c2 + (c1 - ((c2 + c3) + c4)))) diff --git a/tests/coverage/branch/match-arms.coverage b/tests/coverage/branch/match-arms.coverage index c02c86c202e21..912308e720942 100644 --- a/tests/coverage/branch/match-arms.coverage +++ b/tests/coverage/branch/match-arms.coverage @@ -49,8 +49,15 @@ LL| 15| match value { LL| 12| Enum::D(x) | Enum::C(x) => consume(x), ^8 ^4 + ------------------ + | Branch (LL:9): [True: 8, False: 7] + | Branch (LL:22): [True: 4, False: 3] + ------------------ LL| 3| Enum::B(y) | Enum::A(y) => consume(y), ^2 ^1 + ------------------ + | Branch (LL:9): [True: 2, False: 1] + ------------------ LL| | } LL| | LL| 15| consume(0); From 5ccfda997a20bd9943864de9fe166cf0f309a9b2 Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Sun, 29 Sep 2024 14:01:59 +0900 Subject: [PATCH 15/16] Added nested or-pattern test --- .../branch/match-or-pattern-nested.cov-map | 51 +++++++++++++++++++ .../branch/match-or-pattern-nested.coverage | 29 +++++++++++ .../branch/match-or-pattern-nested.rs | 20 ++++++++ 3 files changed, 100 insertions(+) create mode 100644 tests/coverage/branch/match-or-pattern-nested.cov-map create mode 100644 tests/coverage/branch/match-or-pattern-nested.coverage create mode 100644 tests/coverage/branch/match-or-pattern-nested.rs diff --git a/tests/coverage/branch/match-or-pattern-nested.cov-map b/tests/coverage/branch/match-or-pattern-nested.cov-map new file mode 100644 index 0000000000000..c006c325c9cf3 --- /dev/null +++ b/tests/coverage/branch/match-or-pattern-nested.cov-map @@ -0,0 +1,51 @@ +Function name: match_or_pattern_nested::foo +Raw bytes (102): 0x[01, 01, 19, 17, 1d, 27, 19, 53, 15, 57, 11, 09, 0d, 27, 19, 53, 15, 57, 11, 09, 0d, 53, 15, 57, 11, 09, 0d, 57, 11, 09, 0d, 5f, 21, 63, 1d, 15, 19, 57, 11, 09, 0d, 53, 5b, 57, 11, 09, 0d, 5f, 21, 63, 1d, 15, 19, 08, 01, 08, 01, 01, 1c, 20, 21, 03, 02, 0d, 00, 0e, 20, 1d, 17, 00, 11, 00, 12, 20, 19, 27, 00, 1a, 00, 1b, 20, 15, 53, 00, 1e, 00, 1f, 5b, 00, 24, 00, 26, 53, 01, 0e, 00, 10, 4f, 02, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 25 +- expression 0 operands: lhs = Expression(5, Add), rhs = Counter(7) +- expression 1 operands: lhs = Expression(9, Add), rhs = Counter(6) +- expression 2 operands: lhs = Expression(20, Add), rhs = Counter(5) +- expression 3 operands: lhs = Expression(21, Add), rhs = Counter(4) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(6) +- expression 6 operands: lhs = Expression(20, Add), rhs = Counter(5) +- expression 7 operands: lhs = Expression(21, Add), rhs = Counter(4) +- expression 8 operands: lhs = Counter(2), rhs = Counter(3) +- expression 9 operands: lhs = Expression(20, Add), rhs = Counter(5) +- expression 10 operands: lhs = Expression(21, Add), rhs = Counter(4) +- expression 11 operands: lhs = Counter(2), rhs = Counter(3) +- expression 12 operands: lhs = Expression(21, Add), rhs = Counter(4) +- expression 13 operands: lhs = Counter(2), rhs = Counter(3) +- expression 14 operands: lhs = Expression(23, Add), rhs = Counter(8) +- expression 15 operands: lhs = Expression(24, Add), rhs = Counter(7) +- expression 16 operands: lhs = Counter(5), rhs = Counter(6) +- expression 17 operands: lhs = Expression(21, Add), rhs = Counter(4) +- expression 18 operands: lhs = Counter(2), rhs = Counter(3) +- expression 19 operands: lhs = Expression(20, Add), rhs = Expression(22, Add) +- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(4) +- expression 21 operands: lhs = Counter(2), rhs = Counter(3) +- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(8) +- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(7) +- expression 24 operands: lhs = Counter(5), rhs = Counter(6) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 28) +- Branch { true: Counter(8), false: Expression(0, Add) } at (prev + 2, 13) to (start + 0, 14) + true = c8 + false = (((((c2 + c3) + c4) + c5) + c6) + c7) +- Branch { true: Counter(7), false: Expression(5, Add) } at (prev + 0, 17) to (start + 0, 18) + true = c7 + false = ((((c2 + c3) + c4) + c5) + c6) +- Branch { true: Counter(6), false: Expression(9, Add) } at (prev + 0, 26) to (start + 0, 27) + true = c6 + false = (((c2 + c3) + c4) + c5) +- Branch { true: Counter(5), false: Expression(20, Add) } at (prev + 0, 30) to (start + 0, 31) + true = c5 + false = ((c2 + c3) + c4) +- Code(Expression(22, Add)) at (prev + 0, 36) to (start + 0, 38) + = (((c5 + c6) + c7) + c8) +- Code(Expression(20, Add)) at (prev + 1, 14) to (start + 0, 16) + = ((c2 + c3) + c4) +- Code(Expression(19, Add)) at (prev + 2, 1) to (start + 0, 2) + = (((c2 + c3) + c4) + (((c5 + c6) + c7) + c8)) + diff --git a/tests/coverage/branch/match-or-pattern-nested.coverage b/tests/coverage/branch/match-or-pattern-nested.coverage new file mode 100644 index 0000000000000..db00cb99ea35c --- /dev/null +++ b/tests/coverage/branch/match-or-pattern-nested.coverage @@ -0,0 +1,29 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |use core::hint::black_box; + LL| | + LL| 3|fn foo(a: i32, b: i32) { + LL| 3| match black_box((a, b)) { + LL| 2| (1, 2 | 3) | (2, 4 | 5) => {} + ------------------ + | Branch (LL:13): [True: 1, False: 2] + | Branch (LL:17): [True: 0, False: 2] + | Branch (LL:26): [True: 0, False: 2] + | Branch (LL:30): [True: 1, False: 1] + ------------------ + LL| 1| _ => {} + LL| | } + LL| 3|} + LL| | + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | foo(1, 2); + LL| | foo(1, 99); + LL| | foo(2, 5); + LL| |} + LL| | + diff --git a/tests/coverage/branch/match-or-pattern-nested.rs b/tests/coverage/branch/match-or-pattern-nested.rs new file mode 100644 index 0000000000000..5a2f0361578e0 --- /dev/null +++ b/tests/coverage/branch/match-or-pattern-nested.rs @@ -0,0 +1,20 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch +//@ llvm-cov-flags: --show-branches=count + +use core::hint::black_box; + +fn foo(a: i32, b: i32) { + match black_box((a, b)) { + (1, 2 | 3) | (2, 4 | 5) => {} + _ => {} + } +} + +#[coverage(off)] +fn main() { + foo(1, 2); + foo(1, 99); + foo(2, 5); +} From 0fab23dad9423dfc476eb7831e04de25497797ba Mon Sep 17 00:00:00 2001 From: ranger-ross Date: Sun, 29 Sep 2024 14:15:05 +0900 Subject: [PATCH 16/16] More test branch coverage fixes --- tests/coverage/branch/match-arms.coverage | 2 - tests/coverage/branch/match-arms.rs | 2 - .../branch/match-or-pattern-nested.coverage | 2 - tests/coverage/match_or_pattern.cov-map | 184 ++++++++++++------ ...ch_match_arms.main.InstrumentCoverage.diff | 57 ++++-- 5 files changed, 161 insertions(+), 86 deletions(-) diff --git a/tests/coverage/branch/match-arms.coverage b/tests/coverage/branch/match-arms.coverage index 912308e720942..c13bc704e7687 100644 --- a/tests/coverage/branch/match-arms.coverage +++ b/tests/coverage/branch/match-arms.coverage @@ -120,6 +120,4 @@ LL| | call_everything(Enum::D(d)); LL| | } LL| |} - LL| | - LL| |// FIXME(#124118) Support match expressions with or-patterns. diff --git a/tests/coverage/branch/match-arms.rs b/tests/coverage/branch/match-arms.rs index 0cc55e2212b72..e5f78ce33ca3b 100644 --- a/tests/coverage/branch/match-arms.rs +++ b/tests/coverage/branch/match-arms.rs @@ -86,5 +86,3 @@ fn main() { call_everything(Enum::D(d)); } } - -// FIXME(#124118) Support match expressions with or-patterns. diff --git a/tests/coverage/branch/match-or-pattern-nested.coverage b/tests/coverage/branch/match-or-pattern-nested.coverage index db00cb99ea35c..588acb6352b6c 100644 --- a/tests/coverage/branch/match-or-pattern-nested.coverage +++ b/tests/coverage/branch/match-or-pattern-nested.coverage @@ -18,12 +18,10 @@ LL| | } LL| 3|} LL| | - LL| | LL| |#[coverage(off)] LL| |fn main() { LL| | foo(1, 2); LL| | foo(1, 99); LL| | foo(2, 5); LL| |} - LL| | diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map index 60b7024533d2e..ec859372c4599 100644 --- a/tests/coverage/match_or_pattern.cov-map +++ b/tests/coverage/match_or_pattern.cov-map @@ -1,75 +1,135 @@ Function name: match_or_pattern::main -Raw bytes (185): 0x[01, 01, 1c, 01, 05, 09, 0d, 23, 11, 09, 0d, 1f, 15, 23, 11, 09, 0d, 23, 11, 09, 0d, 19, 1d, 43, 21, 19, 1d, 3f, 25, 43, 21, 19, 1d, 43, 21, 19, 1d, 29, 2d, 63, 31, 29, 2d, 5f, 35, 63, 31, 29, 2d, 63, 31, 29, 2d, 39, 3d, 6f, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 01, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 23, 01, 0e, 00, 10, 1f, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 06, 00, 07, 1f, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 43, 01, 0e, 00, 10, 3f, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 32, 03, 06, 00, 07, 3f, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 63, 01, 0e, 00, 10, 5f, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 52, 03, 06, 00, 07, 5f, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 6f, 01, 0e, 00, 10, 6b, 02, 01, 00, 02] +Raw bytes (366): 0x[01, 01, 54, 01, 05, 5f, 25, 63, 21, 19, 1d, 57, 15, 0d, 11, 53, 5b, 57, 15, 0d, 11, 5f, 25, 63, 21, 19, 1d, 4f, 29, 53, 5b, 57, 15, 0d, 11, 5f, 25, 63, 21, 19, 1d, 53, 5b, 57, 15, 0d, 11, 5f, 25, 63, 21, 19, 1d, bf, 01, 49, c3, 01, 45, 3d, 41, b7, 01, 39, 31, 35, b3, 01, bb, 01, b7, 01, 39, 31, 35, bf, 01, 49, c3, 01, 45, 3d, 41, af, 01, 4d, b3, 01, bb, 01, b7, 01, 39, 31, 35, bf, 01, 49, c3, 01, 45, 3d, 41, b3, 01, bb, 01, b7, 01, 39, 31, 35, bf, 01, 49, c3, 01, 45, 3d, 41, 9f, 02, 6d, a3, 02, 69, 61, 65, 97, 02, 5d, 55, 59, 93, 02, 9b, 02, 97, 02, 5d, 55, 59, 9f, 02, 6d, a3, 02, 69, 61, 65, 8f, 02, 71, 93, 02, 9b, 02, 97, 02, 5d, 55, 59, 9f, 02, 6d, a3, 02, 69, 61, 65, 93, 02, 9b, 02, 97, 02, 5d, 55, 59, 9f, 02, 6d, a3, 02, 69, 61, 65, cb, 02, 91, 01, cf, 02, 8d, 01, 85, 01, 89, 01, c3, 02, 81, 01, 79, 7d, bf, 02, c7, 02, c3, 02, 81, 01, 79, 7d, cb, 02, 91, 01, cf, 02, 8d, 01, 85, 01, 89, 01, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 01, 01, 0b, 00, 11, 5b, 03, 1b, 00, 1d, 53, 01, 0e, 00, 10, 4f, 02, 08, 00, 0f, 29, 00, 10, 03, 06, 32, 03, 06, 00, 07, 4f, 01, 0b, 00, 11, bb, 01, 01, 1b, 00, 1d, b3, 01, 01, 0e, 00, 10, af, 01, 02, 08, 00, 0f, 4d, 00, 10, 03, 06, 92, 01, 03, 06, 00, 07, af, 01, 01, 0b, 00, 11, 9b, 02, 01, 1b, 00, 1d, 93, 02, 01, 0e, 00, 10, 8f, 02, 02, 08, 00, 0f, 71, 00, 10, 03, 06, f2, 01, 03, 06, 00, 07, 8f, 02, 01, 0b, 00, 11, c7, 02, 01, 1b, 00, 1d, bf, 02, 01, 0e, 00, 10, bb, 02, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 28 +Number of expressions: 84 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(2), rhs = Counter(3) -- expression 2 operands: lhs = Expression(8, Add), rhs = Counter(4) -- expression 3 operands: lhs = Counter(2), rhs = Counter(3) -- expression 4 operands: lhs = Expression(7, Add), rhs = Counter(5) -- expression 5 operands: lhs = Expression(8, Add), rhs = Counter(4) -- expression 6 operands: lhs = Counter(2), rhs = Counter(3) -- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(4) -- expression 8 operands: lhs = Counter(2), rhs = Counter(3) -- expression 9 operands: lhs = Counter(6), rhs = Counter(7) -- expression 10 operands: lhs = Expression(16, Add), rhs = Counter(8) +- expression 1 operands: lhs = Expression(23, Add), rhs = Counter(9) +- expression 2 operands: lhs = Expression(24, Add), rhs = Counter(8) +- expression 3 operands: lhs = Counter(6), rhs = Counter(7) +- expression 4 operands: lhs = Expression(21, Add), rhs = Counter(5) +- expression 5 operands: lhs = Counter(3), rhs = Counter(4) +- expression 6 operands: lhs = Expression(20, Add), rhs = Expression(22, Add) +- expression 7 operands: lhs = Expression(21, Add), rhs = Counter(5) +- expression 8 operands: lhs = Counter(3), rhs = Counter(4) +- expression 9 operands: lhs = Expression(23, Add), rhs = Counter(9) +- expression 10 operands: lhs = Expression(24, Add), rhs = Counter(8) - expression 11 operands: lhs = Counter(6), rhs = Counter(7) -- expression 12 operands: lhs = Expression(15, Add), rhs = Counter(9) -- expression 13 operands: lhs = Expression(16, Add), rhs = Counter(8) -- expression 14 operands: lhs = Counter(6), rhs = Counter(7) -- expression 15 operands: lhs = Expression(16, Add), rhs = Counter(8) -- expression 16 operands: lhs = Counter(6), rhs = Counter(7) -- expression 17 operands: lhs = Counter(10), rhs = Counter(11) -- expression 18 operands: lhs = Expression(24, Add), rhs = Counter(12) -- expression 19 operands: lhs = Counter(10), rhs = Counter(11) -- expression 20 operands: lhs = Expression(23, Add), rhs = Counter(13) -- expression 21 operands: lhs = Expression(24, Add), rhs = Counter(12) -- expression 22 operands: lhs = Counter(10), rhs = Counter(11) -- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(12) -- expression 24 operands: lhs = Counter(10), rhs = Counter(11) -- expression 25 operands: lhs = Counter(14), rhs = Counter(15) -- expression 26 operands: lhs = Expression(27, Add), rhs = Counter(16) -- expression 27 operands: lhs = Counter(14), rhs = Counter(15) +- expression 12 operands: lhs = Expression(19, Add), rhs = Counter(10) +- expression 13 operands: lhs = Expression(20, Add), rhs = Expression(22, Add) +- expression 14 operands: lhs = Expression(21, Add), rhs = Counter(5) +- expression 15 operands: lhs = Counter(3), rhs = Counter(4) +- expression 16 operands: lhs = Expression(23, Add), rhs = Counter(9) +- expression 17 operands: lhs = Expression(24, Add), rhs = Counter(8) +- expression 18 operands: lhs = Counter(6), rhs = Counter(7) +- expression 19 operands: lhs = Expression(20, Add), rhs = Expression(22, Add) +- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(5) +- expression 21 operands: lhs = Counter(3), rhs = Counter(4) +- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(9) +- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(8) +- expression 24 operands: lhs = Counter(6), rhs = Counter(7) +- expression 25 operands: lhs = Expression(47, Add), rhs = Counter(18) +- expression 26 operands: lhs = Expression(48, Add), rhs = Counter(17) +- expression 27 operands: lhs = Counter(15), rhs = Counter(16) +- expression 28 operands: lhs = Expression(45, Add), rhs = Counter(14) +- expression 29 operands: lhs = Counter(12), rhs = Counter(13) +- expression 30 operands: lhs = Expression(44, Add), rhs = Expression(46, Add) +- expression 31 operands: lhs = Expression(45, Add), rhs = Counter(14) +- expression 32 operands: lhs = Counter(12), rhs = Counter(13) +- expression 33 operands: lhs = Expression(47, Add), rhs = Counter(18) +- expression 34 operands: lhs = Expression(48, Add), rhs = Counter(17) +- expression 35 operands: lhs = Counter(15), rhs = Counter(16) +- expression 36 operands: lhs = Expression(43, Add), rhs = Counter(19) +- expression 37 operands: lhs = Expression(44, Add), rhs = Expression(46, Add) +- expression 38 operands: lhs = Expression(45, Add), rhs = Counter(14) +- expression 39 operands: lhs = Counter(12), rhs = Counter(13) +- expression 40 operands: lhs = Expression(47, Add), rhs = Counter(18) +- expression 41 operands: lhs = Expression(48, Add), rhs = Counter(17) +- expression 42 operands: lhs = Counter(15), rhs = Counter(16) +- expression 43 operands: lhs = Expression(44, Add), rhs = Expression(46, Add) +- expression 44 operands: lhs = Expression(45, Add), rhs = Counter(14) +- expression 45 operands: lhs = Counter(12), rhs = Counter(13) +- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(18) +- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(17) +- expression 48 operands: lhs = Counter(15), rhs = Counter(16) +- expression 49 operands: lhs = Expression(71, Add), rhs = Counter(27) +- expression 50 operands: lhs = Expression(72, Add), rhs = Counter(26) +- expression 51 operands: lhs = Counter(24), rhs = Counter(25) +- expression 52 operands: lhs = Expression(69, Add), rhs = Counter(23) +- expression 53 operands: lhs = Counter(21), rhs = Counter(22) +- expression 54 operands: lhs = Expression(68, Add), rhs = Expression(70, Add) +- expression 55 operands: lhs = Expression(69, Add), rhs = Counter(23) +- expression 56 operands: lhs = Counter(21), rhs = Counter(22) +- expression 57 operands: lhs = Expression(71, Add), rhs = Counter(27) +- expression 58 operands: lhs = Expression(72, Add), rhs = Counter(26) +- expression 59 operands: lhs = Counter(24), rhs = Counter(25) +- expression 60 operands: lhs = Expression(67, Add), rhs = Counter(28) +- expression 61 operands: lhs = Expression(68, Add), rhs = Expression(70, Add) +- expression 62 operands: lhs = Expression(69, Add), rhs = Counter(23) +- expression 63 operands: lhs = Counter(21), rhs = Counter(22) +- expression 64 operands: lhs = Expression(71, Add), rhs = Counter(27) +- expression 65 operands: lhs = Expression(72, Add), rhs = Counter(26) +- expression 66 operands: lhs = Counter(24), rhs = Counter(25) +- expression 67 operands: lhs = Expression(68, Add), rhs = Expression(70, Add) +- expression 68 operands: lhs = Expression(69, Add), rhs = Counter(23) +- expression 69 operands: lhs = Counter(21), rhs = Counter(22) +- expression 70 operands: lhs = Expression(71, Add), rhs = Counter(27) +- expression 71 operands: lhs = Expression(72, Add), rhs = Counter(26) +- expression 72 operands: lhs = Counter(24), rhs = Counter(25) +- expression 73 operands: lhs = Expression(82, Add), rhs = Counter(36) +- expression 74 operands: lhs = Expression(83, Add), rhs = Counter(35) +- expression 75 operands: lhs = Counter(33), rhs = Counter(34) +- expression 76 operands: lhs = Expression(80, Add), rhs = Counter(32) +- expression 77 operands: lhs = Counter(30), rhs = Counter(31) +- expression 78 operands: lhs = Expression(79, Add), rhs = Expression(81, Add) +- expression 79 operands: lhs = Expression(80, Add), rhs = Counter(32) +- expression 80 operands: lhs = Counter(30), rhs = Counter(31) +- expression 81 operands: lhs = Expression(82, Add), rhs = Counter(36) +- expression 82 operands: lhs = Expression(83, Add), rhs = Counter(35) +- expression 83 operands: lhs = Counter(33), rhs = Counter(34) 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(Counter(0)) at (prev + 1, 11) to (start + 0, 17) -- Code(Counter(4)) at (prev + 3, 27) to (start + 0, 29) -- Code(Expression(8, Add)) at (prev + 1, 14) to (start + 0, 16) - = (c2 + c3) -- Code(Expression(7, 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(4, Sub)) at (prev + 3, 6) to (start + 0, 7) - = (((c2 + c3) + c4) - c5) -- Code(Expression(7, Add)) at (prev + 1, 11) to (start + 0, 17) - = ((c2 + c3) + c4) -- Code(Counter(8)) at (prev + 1, 27) to (start + 0, 29) -- Code(Expression(16, Add)) at (prev + 1, 14) to (start + 0, 16) - = (c6 + c7) -- Code(Expression(15, 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(22, Add)) at (prev + 3, 27) to (start + 0, 29) + = (((c6 + c7) + c8) + c9) +- Code(Expression(20, Add)) at (prev + 1, 14) to (start + 0, 16) + = ((c3 + c4) + c5) +- Code(Expression(19, Add)) at (prev + 2, 8) to (start + 0, 15) + = (((c3 + c4) + c5) + (((c6 + c7) + c8) + c9)) +- Code(Counter(10)) at (prev + 0, 16) to (start + 3, 6) - Code(Expression(12, Sub)) at (prev + 3, 6) to (start + 0, 7) - = (((c6 + c7) + c8) - c9) -- Code(Expression(15, Add)) at (prev + 1, 11) to (start + 0, 17) - = ((c6 + c7) + c8) -- Code(Counter(12)) at (prev + 1, 27) to (start + 0, 29) -- Code(Expression(24, Add)) at (prev + 1, 14) to (start + 0, 16) - = (c10 + c11) -- Code(Expression(23, 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(20, Sub)) at (prev + 3, 6) to (start + 0, 7) - = (((c10 + c11) + c12) - c13) -- Code(Expression(23, Add)) at (prev + 1, 11) to (start + 0, 17) - = ((c10 + c11) + c12) -- Code(Counter(16)) at (prev + 1, 27) to (start + 0, 29) -- Code(Expression(27, Add)) at (prev + 1, 14) to (start + 0, 16) - = (c14 + c15) -- Code(Expression(26, Add)) at (prev + 2, 1) to (start + 0, 2) - = ((c14 + c15) + c16) + = ((((c3 + c4) + c5) + (((c6 + c7) + c8) + c9)) - c10) +- Code(Expression(19, Add)) at (prev + 1, 11) to (start + 0, 17) + = (((c3 + c4) + c5) + (((c6 + c7) + c8) + c9)) +- Code(Expression(46, Add)) at (prev + 1, 27) to (start + 0, 29) + = (((c15 + c16) + c17) + c18) +- Code(Expression(44, Add)) at (prev + 1, 14) to (start + 0, 16) + = ((c12 + c13) + c14) +- Code(Expression(43, Add)) at (prev + 2, 8) to (start + 0, 15) + = (((c12 + c13) + c14) + (((c15 + c16) + c17) + c18)) +- Code(Counter(19)) at (prev + 0, 16) to (start + 3, 6) +- Code(Expression(36, Sub)) at (prev + 3, 6) to (start + 0, 7) + = ((((c12 + c13) + c14) + (((c15 + c16) + c17) + c18)) - c19) +- Code(Expression(43, Add)) at (prev + 1, 11) to (start + 0, 17) + = (((c12 + c13) + c14) + (((c15 + c16) + c17) + c18)) +- Code(Expression(70, Add)) at (prev + 1, 27) to (start + 0, 29) + = (((c24 + c25) + c26) + c27) +- Code(Expression(68, Add)) at (prev + 1, 14) to (start + 0, 16) + = ((c21 + c22) + c23) +- Code(Expression(67, Add)) at (prev + 2, 8) to (start + 0, 15) + = (((c21 + c22) + c23) + (((c24 + c25) + c26) + c27)) +- Code(Counter(28)) at (prev + 0, 16) to (start + 3, 6) +- Code(Expression(60, Sub)) at (prev + 3, 6) to (start + 0, 7) + = ((((c21 + c22) + c23) + (((c24 + c25) + c26) + c27)) - c28) +- Code(Expression(67, Add)) at (prev + 1, 11) to (start + 0, 17) + = (((c21 + c22) + c23) + (((c24 + c25) + c26) + c27)) +- Code(Expression(81, Add)) at (prev + 1, 27) to (start + 0, 29) + = (((c33 + c34) + c35) + c36) +- Code(Expression(79, Add)) at (prev + 1, 14) to (start + 0, 16) + = ((c30 + c31) + c32) +- Code(Expression(78, Add)) at (prev + 2, 1) to (start + 0, 2) + = (((c30 + c31) + c32) + (((c33 + c34) + c35) + c36)) diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index 3bd18339ec51f..bcfa31e550f11 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -1,6 +1,6 @@ - // MIR for `main` before InstrumentCoverage + // MIR for `main` after InstrumentCoverage - + fn main() -> () { let mut _0: (); let mut _1: Enum; @@ -25,20 +25,33 @@ scope 4 { debug a => _9; } - + + coverage branches { + BlockMarkerId(0), BlockMarkerId(1) => $DIR/branch_match_arms.rs:16:9: 16:19 (#0) + BlockMarkerId(2), BlockMarkerId(3) => $DIR/branch_match_arms.rs:17:9: 17:19 (#0) + BlockMarkerId(4), BlockMarkerId(5) => $DIR/branch_match_arms.rs:18:9: 18:19 (#0) + BlockMarkerId(6), BlockMarkerId(7) => $DIR/branch_match_arms.rs:19:9: 19:19 (#0) + } + + coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) }; + coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) }; + coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) }; + coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) }; + coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) }; + coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) }; ++ coverage ExpressionId(6) => Expression { lhs: Expression(2), op: Add, rhs: Counter(1) }; ++ coverage ExpressionId(7) => Expression { lhs: Expression(6), op: Add, rhs: Counter(2) }; ++ coverage ExpressionId(8) => Expression { lhs: Expression(7), op: Add, rhs: Counter(3) }; ++ coverage Branch { true_term: Counter(1), false_term: Expression(2) } => $DIR/branch_match_arms.rs:18:9 - 18:19; ++ coverage Branch { true_term: Counter(2), false_term: Expression(6) } => $DIR/branch_match_arms.rs:17:9 - 17:19; ++ coverage Branch { true_term: Counter(3), false_term: Expression(7) } => $DIR/branch_match_arms.rs:16:9 - 16:19; + coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21; + coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33; + coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33; + coverage Code(Counter(1)) => $DIR/branch_match_arms.rs:18:17 - 18:33; + coverage Code(Expression(2)) => $DIR/branch_match_arms.rs:19:17 - 19:33; + coverage Code(Expression(5)) => $DIR/branch_match_arms.rs:21:1 - 21:2; -+ ++ bb0: { + Coverage::CounterIncrement(0); StorageLive(_1); @@ -47,92 +60,100 @@ _2 = discriminant(_1); switchInt(move _2) -> [0: bb5, 1: bb4, 2: bb3, 3: bb2, otherwise: bb1]; } - + bb1: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - + bb2: { + Coverage::CounterIncrement(3); falseEdge -> [real: bb8, imaginary: bb3]; } - + bb3: { + Coverage::CounterIncrement(2); falseEdge -> [real: bb7, imaginary: bb4]; } - + bb4: { + Coverage::CounterIncrement(1); falseEdge -> [real: bb6, imaginary: bb5]; } - + bb5: { + Coverage::ExpressionUsed(2); StorageLive(_9); _9 = copy ((_1 as A).0: u32); StorageLive(_10); _10 = copy _9; + Coverage::BlockMarker(6); + Coverage::BlockMarker(7); _0 = consume(move _10) -> [return: bb12, unwind: bb14]; } - + bb6: { StorageLive(_7); _7 = copy ((_1 as B).0: u32); StorageLive(_8); _8 = copy _7; + Coverage::BlockMarker(4); + Coverage::BlockMarker(5); _0 = consume(move _8) -> [return: bb11, unwind: bb14]; } - + bb7: { StorageLive(_5); _5 = copy ((_1 as C).0: u32); StorageLive(_6); _6 = copy _5; + Coverage::BlockMarker(2); + Coverage::BlockMarker(3); _0 = consume(move _6) -> [return: bb10, unwind: bb14]; } - + bb8: { StorageLive(_3); _3 = copy ((_1 as D).0: u32); StorageLive(_4); _4 = copy _3; + Coverage::BlockMarker(0); + Coverage::BlockMarker(1); _0 = consume(move _4) -> [return: bb9, unwind: bb14]; } - + bb9: { StorageDead(_4); StorageDead(_3); goto -> bb13; } - + bb10: { StorageDead(_6); StorageDead(_5); goto -> bb13; } - + bb11: { StorageDead(_8); StorageDead(_7); goto -> bb13; } - + bb12: { StorageDead(_10); StorageDead(_9); goto -> bb13; } - + bb13: { + Coverage::ExpressionUsed(5); StorageDead(_1); return; } - + bb14 (cleanup): { resume; } } - +