Skip to content

Commit f2f6704

Browse files
author
zhuyunxing
committed
coverage. Instrument mcdc for pattern matching
1 parent 8bbe36f commit f2f6704

File tree

17 files changed

+3718
-27
lines changed

17 files changed

+3718
-27
lines changed

compiler/rustc_middle/src/mir/coverage.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ pub struct BranchSpan {
300300
pub false_marker: BlockMarkerId,
301301
}
302302

303-
#[derive(Copy, Clone, Debug)]
303+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
304304
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
305305
pub struct ConditionInfo {
306306
pub condition_id: ConditionId,
@@ -389,8 +389,10 @@ impl Default for CandidateCovId {
389389
}
390390

391391
impl CandidateCovId {
392-
pub fn is_valid(&self) -> bool {
393-
*self != Self::default()
392+
/// Return `true` is this `CandidateCovId` is assigned properly through coverage mechanism
393+
/// and can be mapped as a decision.
394+
pub fn is_valid(self) -> bool {
395+
self != Self::default()
394396
}
395397

396398
pub fn new_match_info(

compiler/rustc_mir_build/src/build/coverageinfo.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,9 @@ impl CoverageInfoBuilder {
184184
num_block_markers,
185185
branch_spans,
186186
mcdc_degraded_spans,
187-
mcdc_spans
188-
})
189-
}
187+
mcdc_spans,
188+
})
189+
}
190190
}
191191

192192
impl<'tcx> Builder<'_, 'tcx> {

compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
mod matching;
12
use std::cell::Cell;
23
use std::collections::VecDeque;
34
use std::rc::Rc;
45

6+
use matching::{LateMatchingState, MatchingDecisionCtx};
57
use rustc_data_structures::fx::FxIndexMap;
68
use rustc_middle::bug;
79
use rustc_middle::mir::BasicBlock;
@@ -174,14 +176,17 @@ impl BooleanDecisionCtx {
174176
#[derive(Debug)]
175177
enum DecisionCtx {
176178
Boolean(BooleanDecisionCtx),
177-
#[allow(unused)]
178-
Matching,
179+
Matching(MatchingDecisionCtx),
179180
}
180181

181182
impl DecisionCtx {
182183
fn new_boolean(id: DecisionId) -> Self {
183184
Self::Boolean(BooleanDecisionCtx::new(id))
184185
}
186+
187+
fn new_matching(info: &[(Span, DecisionId)]) -> Self {
188+
Self::Matching(MatchingDecisionCtx::new(info))
189+
}
185190
}
186191

187192
pub(crate) struct MCDCStateGuard {
@@ -270,6 +275,7 @@ pub(crate) struct MCDCInfoBuilder {
270275
normal_branch_spans: Vec<MCDCBranchSpan>,
271276
mcdc_targets: FxIndexMap<DecisionId, MCDCTargetInfo>,
272277
state_stack: Vec<MCDCState>,
278+
late_matching_state: LateMatchingState,
273279
decision_id_gen: DecisionIdGen,
274280
}
275281

@@ -279,6 +285,7 @@ impl MCDCInfoBuilder {
279285
normal_branch_spans: vec![],
280286
mcdc_targets: FxIndexMap::default(),
281287
state_stack: vec![],
288+
late_matching_state: Default::default(),
282289
decision_id_gen: DecisionIdGen::default(),
283290
}
284291
}
@@ -293,6 +300,11 @@ impl MCDCInfoBuilder {
293300
&mut self.state_stack[current_idx]
294301
}
295302

303+
fn current_processing_ctx_mut(&mut self) -> Option<&mut DecisionCtx> {
304+
self.ensure_active_state();
305+
self.state_stack.last_mut().and_then(|state| state.current_ctx.as_mut())
306+
}
307+
296308
fn ensure_active_state(&mut self) {
297309
let mut active_state_idx = None;
298310
// Down to the first non-stashed state or non-empty state, which can be ensured to be
@@ -353,7 +365,8 @@ impl MCDCInfoBuilder {
353365
let num_conditions = info.conditions.len();
354366
match num_conditions {
355367
0 => {
356-
unreachable!("Decision with no condition is not expected");
368+
// Irrefutable patterns caused by empty types can lead to here.
369+
false
357370
}
358371
// Ignore decisions with only one condition given that mcdc for them is completely equivalent to branch coverage.
359372
2..=MAX_CONDITIONS_IN_DECISION => {
@@ -445,17 +458,26 @@ impl MCDCInfoBuilder {
445458

446459
let (id, decision, conditions) = ctx.into_done();
447460
let info = MCDCTargetInfo { decision, conditions, nested_decisions_id };
448-
let entry_decision_id = self.append_mcdc_info(tcx, id, info).then_some(id);
449-
self.on_ctx_finished(tcx, entry_decision_id);
461+
if self.late_matching_state.is_guard_decision(id) {
462+
self.late_matching_state.add_guard_decision(id, info);
463+
} else {
464+
let entry_id = self.append_mcdc_info(tcx, id, info).then_some(id);
465+
self.on_ctx_finished(tcx, entry_id)
466+
}
450467
}
451468

452469
pub(crate) fn into_done(
453470
self,
454471
) -> (Vec<MCDCBranchSpan>, Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>) {
472+
assert!(
473+
!self.has_processing_decision() && self.late_matching_state.is_empty(),
474+
"has unfinished decisions"
475+
);
455476
let MCDCInfoBuilder {
456477
normal_branch_spans,
457478
mcdc_targets,
458479
state_stack: _,
480+
late_matching_state: _,
459481
decision_id_gen: _,
460482
} = self;
461483

0 commit comments

Comments
 (0)