@@ -22,6 +22,7 @@ struct MCDCDecisionCtx {
2222 /// To construct condition evaluation tree.
2323 decision_stack : VecDeque < ConditionInfo > ,
2424 processing_decision : Option < MCDCDecisionSpan > ,
25+ conditions : Vec < MCDCBranchSpan > ,
2526}
2627
2728struct MCDCState {
@@ -100,9 +101,9 @@ impl MCDCState {
100101 }
101102 None => decision_ctx. processing_decision . insert ( MCDCDecisionSpan {
102103 span,
103- num_conditions : 0 ,
104104 end_markers : vec ! [ ] ,
105105 decision_depth,
106+ num_conditions : 0 ,
106107 } ) ,
107108 } ;
108109
@@ -155,16 +156,29 @@ impl MCDCState {
155156 decision_ctx. decision_stack . push_back ( lhs) ;
156157 }
157158
158- fn take_condition (
159+ fn try_finish_decision (
159160 & mut self ,
161+ span : Span ,
160162 true_marker : BlockMarkerId ,
161163 false_marker : BlockMarkerId ,
162- ) -> ( Option < ConditionInfo > , Option < MCDCDecisionSpan > ) {
164+ degraded_branches : & mut Vec < MCDCBranchSpan > ,
165+ ) -> Option < ( MCDCDecisionSpan , Vec < MCDCBranchSpan > ) > {
163166 let Some ( decision_ctx) = self . decision_ctx_stack . last_mut ( ) else {
164167 bug ! ( "Unexpected empty decision_ctx_stack" )
165168 } ;
166169 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 ;
168182 } ;
169183 let Some ( decision) = decision_ctx. processing_decision . as_mut ( ) else {
170184 bug ! ( "Processing decision should have been created before any conditions are taken" ) ;
@@ -175,24 +189,31 @@ impl MCDCState {
175189 if condition_info. false_next_id . is_none ( ) {
176190 decision. end_markers . push ( false_marker) ;
177191 }
192+ decision_ctx. conditions . push ( MCDCBranchSpan {
193+ span,
194+ condition_info,
195+ true_marker,
196+ false_marker,
197+ } ) ;
178198
179199 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) )
181202 } else {
182- ( Some ( condition_info ) , None )
203+ None
183204 }
184205 }
185206}
186207
187208pub ( 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 > ) > ,
190211 state : MCDCState ,
191212}
192213
193214impl MCDCInfoBuilder {
194215 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 ( ) }
196217 }
197218
198219 pub ( crate ) fn visit_evaluated_condition (
@@ -206,50 +227,44 @@ impl MCDCInfoBuilder {
206227 let true_marker = inject_block_marker ( source_info, true_block) ;
207228 let false_marker = inject_block_marker ( source_info, false_block) ;
208229
209- let decision_depth = self . state . decision_depth ( ) ;
210- let ( mut condition_info, decision_result) =
211- self . state . take_condition ( true_marker, false_marker) ;
212230 // take_condition() returns Some for decision_result when the decision stack
213231 // is empty, i.e. when all the conditions of the decision were instrumented,
214232 // 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 {
217245 0 => {
218246 unreachable ! ( "Decision with no condition is not expected" ) ;
219247 }
220248 1 ..=MAX_CONDITIONS_IN_DECISION => {
221- self . decision_spans . push ( decision) ;
249+ self . mcdc_spans . push ( ( decision, conditions ) ) ;
222250 }
223251 _ => {
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) ;
233253
234254 tcx. dcx ( ) . emit_warn ( MCDCExceedsConditionLimit {
235255 span : decision. span ,
236- num_conditions : decision . num_conditions ,
256+ num_conditions,
237257 max_conditions : MAX_CONDITIONS_IN_DECISION ,
238258 } ) ;
239259 }
240260 }
241261 }
242- self . branch_spans . push ( MCDCBranchSpan {
243- span : source_info. span ,
244- condition_info,
245- true_marker,
246- false_marker,
247- decision_depth,
248- } ) ;
249262 }
250263
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 )
253268 }
254269}
255270
0 commit comments