@@ -153,7 +153,7 @@ void dfcc_check_loop_normal_form(goto_programt &goto_program, messaget &log)
153153 // IF g THEN GOTO HEAD
154154 // --------------------------
155155 // IF !g THEN GOTO EXIT
156- // GOTO HEAD
156+ // IF TRUE GOTO HEAD
157157 // EXIT: SKIP
158158 // ```
159159 if (latch->has_condition () && !latch->condition ().is_true ())
@@ -162,24 +162,38 @@ void dfcc_check_loop_normal_form(goto_programt &goto_program, messaget &log)
162162 const auto &exit =
163163 goto_program.insert_after (latch, goto_programt::make_skip (loc));
164164
165+ // Insert the loop exit jump `F !g THEN GOTO EXIT`
165166 insert_before_and_update_jumps (
166167 goto_program,
167168 latch,
168169 goto_programt::make_goto (
169170 exit, not_exprt (latch->condition ()), latch->source_location ()));
170171
171- // CAUTION: The condition expression needs to be updated in place because
172- // this is where loop contract clauses are stored as extra ireps.
173- // Overwriting this expression with a fresh expression will also lose the
174- // loop contract.
175- exprt latch_condition = latch->condition ();
176- latch_condition.set (ID_value, ID_true);
177- *latch = goto_programt::make_goto (head, latch_condition, loc);
178- }
172+ // Rewrite the latch node `IF g THEN GOTO HEAD`
173+ // into `IF true THEN GOTO HEAD`
174+ // and transplanting contract clauses
175+ exprt new_condition = true_exprt ();
176+
177+ // Extract the contract clauses from the existing latch condition,
178+ const exprt &latch_condition = latch->condition ();
179+ irept latch_assigns = latch_condition.find (ID_C_spec_assigns);
180+ if (latch_assigns.is_not_nil ())
181+ new_condition.add (ID_C_spec_assigns).swap (latch_assigns);
182+
183+ irept latch_loop_invariant =
184+ latch_condition.find (ID_C_spec_loop_invariant);
185+ if (latch_loop_invariant.is_not_nil ())
186+ new_condition.add (ID_C_spec_loop_invariant).swap (latch_loop_invariant);
179187
180- // The latch node is now an unconditional jump.
188+ irept latch_decreases = latch_condition.find (ID_C_spec_decreases);
189+ if (latch_decreases.is_not_nil ())
190+ new_condition.add (ID_C_spec_decreases).swap (latch_decreases);
191+
192+ latch->condition_nonconst () = new_condition;
193+ // The latch node is now an unconditional jump with contract clauses
194+ }
181195
182- // insert a SKIP pre-head node and reroute all incoming edges to that node,
196+ // Insert a SKIP pre-head node and reroute all incoming edges to that node,
183197 // except for edge coming from the latch.
184198 insert_before_and_update_jumps (
185199 goto_program, head, goto_programt::make_skip (head->source_location ()));
0 commit comments