Skip to content

Commit a15835e

Browse files
committed
mcdc-coverage: Use decision context stack to handle nested decisions.
- Introduce MCDCDecisionCtx - Use a stack of MCDCDecisionCtx to handle nested decisions
1 parent 5d4db48 commit a15835e

File tree

1 file changed

+40
-20
lines changed

1 file changed

+40
-20
lines changed

compiler/rustc_mir_build/src/build/coverageinfo.rs

+40-20
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,12 @@ impl BranchInfoBuilder {
103103
false_marker: BlockMarkerId,
104104
) -> Option<(u16, ConditionInfo)> {
105105
let mcdc_state = self.mcdc_state.as_mut()?;
106-
let decision_depth = mcdc_state.decision_depth;
106+
let decision_depth = mcdc_state.decision_depth();
107107
let (mut condition_info, decision_result) =
108108
mcdc_state.take_condition(true_marker, false_marker);
109+
// take_condition() returns Some for decision_result when the decision stack
110+
// is empty, i.e. when all the conditions of the decision were instrumented,
111+
// and the decision is "complete".
109112
if let Some(decision) = decision_result {
110113
match decision.conditions_num {
111114
0 => {
@@ -200,20 +203,27 @@ impl BranchInfoBuilder {
200203
/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged.
201204
const MAX_CONDITIONS_NUM_IN_DECISION: usize = 6;
202205

203-
struct MCDCState {
206+
#[derive(Default)]
207+
struct MCDCDecisionCtx {
204208
/// To construct condition evaluation tree.
205209
decision_stack: VecDeque<ConditionInfo>,
206210
processing_decision: Option<MCDCDecisionSpan>,
207-
decision_depth: u16,
211+
}
212+
213+
struct MCDCState {
214+
decision_ctx_stack: Vec<MCDCDecisionCtx>,
208215
}
209216

210217
impl MCDCState {
211218
fn new_if_enabled(tcx: TyCtxt<'_>) -> Option<Self> {
212-
tcx.sess.instrument_coverage_mcdc().then(|| Self {
213-
decision_stack: VecDeque::new(),
214-
processing_decision: None,
215-
decision_depth: 0,
216-
})
219+
tcx.sess
220+
.instrument_coverage_mcdc()
221+
.then(|| Self { decision_ctx_stack: vec![MCDCDecisionCtx::default()] })
222+
}
223+
224+
#[inline]
225+
fn decision_depth(&self) -> u16 {
226+
(self.decision_ctx_stack.len() - 1) as u16
217227
}
218228

219229
// At first we assign ConditionIds for each sub expression.
@@ -257,20 +267,23 @@ impl MCDCState {
257267
// - If the op is AND, the "false_next" of LHS and RHS should be the parent's "false_next". While "true_next" of the LHS is the RHS, the "true next" of RHS is the parent's "true_next".
258268
// - If the op is OR, the "true_next" of LHS and RHS should be the parent's "true_next". While "false_next" of the LHS is the RHS, the "false next" of RHS is the parent's "false_next".
259269
fn record_conditions(&mut self, op: LogicalOp, span: Span) {
260-
let decision = match self.processing_decision.as_mut() {
270+
let decision_depth = self.decision_depth();
271+
let decision_ctx =
272+
self.decision_ctx_stack.last_mut().expect("Unexpected empty decision_ctx_stack");
273+
let decision = match decision_ctx.processing_decision.as_mut() {
261274
Some(decision) => {
262275
decision.span = decision.span.to(span);
263276
decision
264277
}
265-
None => self.processing_decision.insert(MCDCDecisionSpan {
278+
None => decision_ctx.processing_decision.insert(MCDCDecisionSpan {
266279
span,
267280
conditions_num: 0,
268281
end_markers: vec![],
269-
decision_depth: 0,
282+
decision_depth: decision_depth,
270283
}),
271284
};
272285

273-
let parent_condition = self.decision_stack.pop_back().unwrap_or_default();
286+
let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_default();
274287
let lhs_id = if parent_condition.condition_id == ConditionId::NONE {
275288
decision.conditions_num += 1;
276289
ConditionId::from(decision.conditions_num)
@@ -310,19 +323,21 @@ impl MCDCState {
310323
}
311324
};
312325
// We visit expressions tree in pre-order, so place the left-hand side on the top.
313-
self.decision_stack.push_back(rhs);
314-
self.decision_stack.push_back(lhs);
326+
decision_ctx.decision_stack.push_back(rhs);
327+
decision_ctx.decision_stack.push_back(lhs);
315328
}
316329

317330
fn take_condition(
318331
&mut self,
319332
true_marker: BlockMarkerId,
320333
false_marker: BlockMarkerId,
321334
) -> (Option<ConditionInfo>, Option<MCDCDecisionSpan>) {
322-
let Some(condition_info) = self.decision_stack.pop_back() else {
335+
let decision_ctx =
336+
self.decision_ctx_stack.last_mut().expect("Unexpected empty decision_ctx_stack");
337+
let Some(condition_info) = decision_ctx.decision_stack.pop_back() else {
323338
return (None, None);
324339
};
325-
let Some(decision) = self.processing_decision.as_mut() else {
340+
let Some(decision) = decision_ctx.processing_decision.as_mut() else {
326341
bug!("Processing decision should have been created before any conditions are taken");
327342
};
328343
if condition_info.true_next_id == ConditionId::NONE {
@@ -332,8 +347,8 @@ impl MCDCState {
332347
decision.end_markers.push(false_marker);
333348
}
334349

335-
if self.decision_stack.is_empty() {
336-
(Some(condition_info), self.processing_decision.take())
350+
if decision_ctx.decision_stack.is_empty() {
351+
(Some(condition_info), decision_ctx.processing_decision.take())
337352
} else {
338353
(Some(condition_info), None)
339354
}
@@ -399,15 +414,20 @@ impl Builder<'_, '_> {
399414
if let Some(branch_info) = self.coverage_branch_info.as_mut()
400415
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
401416
{
402-
mcdc_state.decision_depth += 1;
417+
mcdc_state.decision_ctx_stack.push(MCDCDecisionCtx::default());
403418
};
404419
}
405420

406421
pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) {
407422
if let Some(branch_info) = self.coverage_branch_info.as_mut()
408423
&& let Some(mcdc_state) = branch_info.mcdc_state.as_mut()
409424
{
410-
mcdc_state.decision_depth -= 1;
425+
#[allow(unused)]
426+
let Some(MCDCDecisionCtx { decision_stack, processing_decision }) =
427+
mcdc_state.decision_ctx_stack.pop()
428+
else {
429+
bug!("Unexpected empty Decision stack");
430+
};
411431
};
412432
}
413433
}

0 commit comments

Comments
 (0)