@@ -22,6 +22,7 @@ struct MCDCDecisionCtx {
22
22
/// To construct condition evaluation tree.
23
23
decision_stack : VecDeque < ConditionInfo > ,
24
24
processing_decision : Option < MCDCDecisionSpan > ,
25
+ conditions : Vec < MCDCBranchSpan > ,
25
26
}
26
27
27
28
struct MCDCState {
@@ -155,16 +156,29 @@ impl MCDCState {
155
156
decision_ctx. decision_stack . push_back ( lhs) ;
156
157
}
157
158
158
- fn take_condition (
159
+ fn try_finish_decision (
159
160
& mut self ,
161
+ span : Span ,
160
162
true_marker : BlockMarkerId ,
161
163
false_marker : BlockMarkerId ,
162
- ) -> ( Option < ConditionInfo > , Option < MCDCDecisionSpan > ) {
164
+ degraded_branches : & mut Vec < MCDCBranchSpan > ,
165
+ ) -> Option < ( MCDCDecisionSpan , Vec < MCDCBranchSpan > ) > {
163
166
let Some ( decision_ctx) = self . decision_ctx_stack . last_mut ( ) else {
164
167
bug ! ( "Unexpected empty decision_ctx_stack" )
165
168
} ;
166
169
let Some ( condition_info) = decision_ctx. decision_stack . pop_back ( ) else {
167
- return ( None , None ) ;
170
+ let branch = MCDCBranchSpan {
171
+ span,
172
+ condition_info : ConditionInfo {
173
+ condition_id : ConditionId :: START ,
174
+ true_next_id : None ,
175
+ false_next_id : None ,
176
+ } ,
177
+ true_marker,
178
+ false_marker,
179
+ } ;
180
+ degraded_branches. push ( branch) ;
181
+ return None ;
168
182
} ;
169
183
let Some ( decision) = decision_ctx. processing_decision . as_mut ( ) else {
170
184
bug ! ( "Processing decision should have been created before any conditions are taken" ) ;
@@ -175,24 +189,31 @@ impl MCDCState {
175
189
if condition_info. false_next_id . is_none ( ) {
176
190
decision. end_markers . push ( false_marker) ;
177
191
}
192
+ decision_ctx. conditions . push ( MCDCBranchSpan {
193
+ span,
194
+ condition_info,
195
+ true_marker,
196
+ false_marker,
197
+ } ) ;
178
198
179
199
if decision_ctx. decision_stack . is_empty ( ) {
180
- ( Some ( condition_info) , decision_ctx. processing_decision . take ( ) )
200
+ let conditions = std:: mem:: take ( & mut decision_ctx. conditions ) ;
201
+ decision_ctx. processing_decision . take ( ) . map ( |decision| ( decision, conditions) )
181
202
} else {
182
- ( Some ( condition_info ) , None )
203
+ None
183
204
}
184
205
}
185
206
}
186
207
187
208
pub ( crate ) struct MCDCInfoBuilder {
188
- branch_spans : Vec < MCDCBranchSpan > ,
189
- decision_spans : Vec < MCDCDecisionSpan > ,
209
+ degraded_spans : Vec < MCDCBranchSpan > ,
210
+ mcdc_spans : Vec < ( MCDCDecisionSpan , Vec < MCDCBranchSpan > ) > ,
190
211
state : MCDCState ,
191
212
}
192
213
193
214
impl MCDCInfoBuilder {
194
215
pub ( crate ) fn new ( ) -> Self {
195
- Self { branch_spans : vec ! [ ] , decision_spans : vec ! [ ] , state : MCDCState :: new ( ) }
216
+ Self { degraded_spans : vec ! [ ] , mcdc_spans : vec ! [ ] , state : MCDCState :: new ( ) }
196
217
}
197
218
198
219
pub ( crate ) fn visit_evaluated_condition (
@@ -206,50 +227,44 @@ impl MCDCInfoBuilder {
206
227
let true_marker = inject_block_marker ( source_info, true_block) ;
207
228
let false_marker = inject_block_marker ( source_info, false_block) ;
208
229
209
- let decision_depth = self . state . decision_depth ( ) ;
210
- let ( mut condition_info, decision_result) =
211
- self . state . take_condition ( true_marker, false_marker) ;
212
230
// take_condition() returns Some for decision_result when the decision stack
213
231
// is empty, i.e. when all the conditions of the decision were instrumented,
214
232
// and the decision is "complete".
215
- if let Some ( decision) = decision_result {
216
- match decision. num_conditions {
233
+ if let Some ( ( decision, conditions) ) = self . state . try_finish_decision (
234
+ source_info. span ,
235
+ true_marker,
236
+ false_marker,
237
+ & mut self . degraded_spans ,
238
+ ) {
239
+ let num_conditions = conditions. len ( ) ;
240
+ assert_eq ! (
241
+ num_conditions, decision. num_conditions,
242
+ "final number of conditions is not correct"
243
+ ) ;
244
+ match num_conditions {
217
245
0 => {
218
246
unreachable ! ( "Decision with no condition is not expected" ) ;
219
247
}
220
248
1 ..=MAX_CONDITIONS_IN_DECISION => {
221
- self . decision_spans . push ( decision) ;
249
+ self . mcdc_spans . push ( ( decision, conditions ) ) ;
222
250
}
223
251
_ => {
224
- // Do not generate mcdc mappings and statements for decisions with too many conditions.
225
- // Therefore, first erase the condition info of the (N-1) previous branch spans.
226
- let rebase_idx = self . branch_spans . len ( ) - ( decision. num_conditions - 1 ) ;
227
- for branch in & mut self . branch_spans [ rebase_idx..] {
228
- branch. condition_info = None ;
229
- }
230
-
231
- // Then, erase this last branch span's info too, for a total of N.
232
- condition_info = None ;
252
+ self . degraded_spans . extend ( conditions) ;
233
253
234
254
tcx. dcx ( ) . emit_warn ( MCDCExceedsConditionLimit {
235
255
span : decision. span ,
236
- num_conditions : decision . num_conditions ,
256
+ num_conditions,
237
257
max_conditions : MAX_CONDITIONS_IN_DECISION ,
238
258
} ) ;
239
259
}
240
260
}
241
261
}
242
- self . branch_spans . push ( MCDCBranchSpan {
243
- span : source_info. span ,
244
- condition_info,
245
- true_marker,
246
- false_marker,
247
- decision_depth,
248
- } ) ;
249
262
}
250
263
251
- pub ( crate ) fn into_done ( self ) -> ( Vec < MCDCDecisionSpan > , Vec < MCDCBranchSpan > ) {
252
- ( self . decision_spans , self . branch_spans )
264
+ pub ( crate ) fn into_done (
265
+ self ,
266
+ ) -> ( Vec < ( MCDCDecisionSpan , Vec < MCDCBranchSpan > ) > , Vec < MCDCBranchSpan > ) {
267
+ ( self . mcdc_spans , self . degraded_spans )
253
268
}
254
269
}
255
270
0 commit comments