@@ -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,37 @@ 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.
172
+ // Rewrite the latch node `IF g THEN GOTO HEAD` into `IF true THEN GOTO HEAD`
173
+ // transplanting contract clauses
174
+ exprt new_condition = true_exprt ();
175
+
176
+ // Extract the contract clauses from the existing latch condition,
175
177
exprt latch_condition = latch->condition ();
176
- latch_condition.set (ID_value, ID_true);
177
- *latch = goto_programt::make_goto (head, latch_condition, loc);
178
- }
178
+ irept latch_assigns = latch_condition.find (ID_C_spec_assigns);
179
+ if (latch_assigns.is_not_nil ())
180
+ new_condition.add (ID_C_spec_assigns).swap (latch_assigns);
181
+
182
+ irept latch_loop_invariant =
183
+ latch_condition.find (ID_C_spec_loop_invariant);
184
+ if (latch_loop_invariant.is_not_nil ())
185
+ new_condition.add (ID_C_spec_loop_invariant).swap (latch_loop_invariant);
179
186
180
- // The latch node is now an unconditional jump.
187
+ irept latch_decreases = latch_condition.find (ID_C_spec_decreases);
188
+ if (latch_decreases.is_not_nil ())
189
+ new_condition.add (ID_C_spec_decreases).swap (latch_decreases);
190
+
191
+ latch->condition_nonconst () = new_condition;
192
+ // The latch node is now an unconditional jump with contract clauses attached
193
+ }
181
194
182
- // insert a SKIP pre-head node and reroute all incoming edges to that node,
195
+ // Insert a SKIP pre-head node and reroute all incoming edges to that node,
183
196
// except for edge coming from the latch.
184
197
insert_before_and_update_jumps (
185
198
goto_program, head, goto_programt::make_skip (head->source_location ()));
0 commit comments