Skip to content

Commit 00978bd

Browse files
author
Remi Delmas
committed
CONTRACTS: fix loop latch nodes normalization
1 parent 3877e0f commit 00978bd

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

regression/contracts/loop_contracts_do_while/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ int main()
77
do
88
// clang-format off
99
__CPROVER_assigns(x)
10-
__CPROVER_loop_invariant(0 <= x && x <= 10)
10+
__CPROVER_loop_invariant(0 <= x && x < 10)
1111
__CPROVER_decreases(20 - x)
1212
// clang-format on
1313
{

src/goto-instrument/contracts/dynamic-frames/dfcc_check_loop_normal_form.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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,37 @@ 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.
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,
175177
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);
179186

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+
}
181194

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,
183196
// except for edge coming from the latch.
184197
insert_before_and_update_jumps(
185198
goto_program, head, goto_programt::make_skip(head->source_location()));

0 commit comments

Comments
 (0)