@@ -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
+ // Extract the contract clauses from the existing latch condition,
166
+ exprt latch_condition = latch->condition ();
167
+
168
+ // Insert the loop exit jump `F !g THEN GOTO EXIT`
165
169
insert_before_and_update_jumps (
166
170
goto_program,
167
171
latch,
168
172
goto_programt::make_goto (
169
- exit, not_exprt (latch-> condition () ), latch->source_location ()));
173
+ exit, not_exprt (latch_condition ), latch->source_location ()));
170
174
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
- }
175
+ // Rewrite the latch node `IF g THEN GOTO HEAD` into `IF true THEN GOTO HEAD`
176
+ // transplanting contract clauses
177
+ exprt new_condition = true_exprt ();
179
178
180
- // The latch node is now an unconditional jump.
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);
187
+
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 attached
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