Skip to content

Commit 0421337

Browse files
zhuyunxingLambdaris
zhuyunxing
authored andcommitted
coverage. Instrument mcdc for pattern matching
1 parent dfaf4a0 commit 0421337

File tree

15 files changed

+3801
-22
lines changed

15 files changed

+3801
-22
lines changed

compiler/rustc_middle/src/mir/coverage.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ pub struct BranchSpan {
276276
pub false_marker: BlockMarkerId,
277277
}
278278

279-
#[derive(Copy, Clone, Debug)]
279+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
280280
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
281281
pub struct ConditionInfo {
282282
pub condition_id: ConditionId,
@@ -402,8 +402,10 @@ impl Default for CandidateCovId {
402402
}
403403

404404
impl CandidateCovId {
405-
pub fn is_valid(&self) -> bool {
406-
*self != Self::default()
405+
/// Return `true` is this `CandidateCovId` is assigned properly through coverage mechanism
406+
/// and can be mapped as a decision.
407+
pub fn is_valid(self) -> bool {
408+
self != Self::default()
407409
}
408410

409411
pub fn new_match_info(

compiler/rustc_mir_build/src/builder/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)