@@ -153,7 +153,7 @@ void dfcc_check_loop_normal_form(goto_programt &goto_program, messaget &log)
153
153
// IF g THEN GOTO HEAD
154
154
// --------------------------
155
155
// IF !g THEN GOTO EXIT
156
- // GOTO HEAD
156
+ // IF TRUE GOTO HEAD
157
157
// EXIT: SKIP
158
158
// ```
159
159
if (latch->has_condition () && !latch->condition ().is_true ())
@@ -162,24 +162,38 @@ void dfcc_check_loop_normal_form(goto_programt &goto_program, messaget &log)
162
162
const auto &exit =
163
163
goto_program.insert_after (latch, goto_programt::make_skip (loc));
164
164
165
+ // Insert the loop exit jump `F !g THEN GOTO EXIT`
165
166
insert_before_and_update_jumps (
166
167
goto_program,
167
168
latch,
168
169
goto_programt::make_goto (
169
170
exit , not_exprt (latch->condition ()), latch->source_location ()));
170
171
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);
179
187
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
+ }
181
195
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,
183
197
// except for edge coming from the latch.
184
198
insert_before_and_update_jumps (
185
199
goto_program, head, goto_programt::make_skip (head->source_location ()));
0 commit comments