@@ -147,6 +147,8 @@ void code_contractst::check_apply_loop_contracts(
147
147
// H: loop;
148
148
// E: ...
149
149
// to
150
+ // process history variables;
151
+ // declare and assign loop_entry variables;
150
152
// H: assert(invariant);
151
153
// havoc;
152
154
// assume(invariant);
@@ -176,6 +178,20 @@ void code_contractst::check_apply_loop_contracts(
176
178
return invariant_copy;
177
179
};
178
180
181
+ // Process "loop_entry" history variables
182
+ // Find and replace "loop_entry" expression in the "invariant" expression.
183
+ std::map<exprt, exprt> parameter2history;
184
+ replace_history_parameter (
185
+ invariant,
186
+ parameter2history,
187
+ loop_head->source_location ,
188
+ mode,
189
+ havoc_code,
190
+ ID_loop_entry);
191
+
192
+ // Create 'loop_entry' history variables
193
+ insert_before_swap_and_advance (goto_function.body , loop_head, havoc_code);
194
+
179
195
// Generate: assert(invariant) just before the loop
180
196
// We use a block scope to create a temporary assertion,
181
197
// and immediately convert it to goto instructions.
@@ -377,24 +393,23 @@ void code_contractst::add_quantified_variable(
377
393
}
378
394
}
379
395
380
- void code_contractst::replace_old_parameter (
396
+ void code_contractst::replace_history_parameter (
381
397
exprt &expr,
382
398
std::map<exprt, exprt> ¶meter2history,
383
399
source_locationt location,
384
400
const irep_idt &mode,
385
- goto_programt &history)
401
+ goto_programt &history,
402
+ const irep_idt &id)
386
403
{
387
404
for (auto &op : expr.operands ())
388
405
{
389
- replace_old_parameter (op, parameter2history, location, mode, history);
406
+ replace_history_parameter (
407
+ op, parameter2history, location, mode, history, id);
390
408
}
391
409
392
- if (expr.id () == ID_old)
410
+ if (expr.id () == ID_old || expr. id () == ID_loop_entry )
393
411
{
394
- DATA_INVARIANT (
395
- expr.operands ().size () == 1 , CPROVER_PREFIX " old must have one operand" );
396
-
397
- const auto ¶meter = to_old_expr (expr).expression ();
412
+ const auto ¶meter = to_history_expr (expr, id).expression ();
398
413
399
414
if (
400
415
parameter.id () == ID_dereference || parameter.id () == ID_member ||
@@ -428,8 +443,8 @@ void code_contractst::replace_old_parameter(
428
443
}
429
444
else
430
445
{
431
- log .error () << CPROVER_PREFIX " old does not currently support "
432
- << parameter. id () << " expressions." << messaget::eom;
446
+ log .error () << " History variables do not support " << parameter. id ()
447
+ << " expressions." << messaget::eom;
433
448
throw 0 ;
434
449
}
435
450
}
@@ -445,7 +460,8 @@ code_contractst::create_ensures_instruction(
445
460
goto_programt history;
446
461
447
462
// Find and replace "old" expression in the "expression" variable
448
- replace_old_parameter (expression, parameter2history, location, mode, history);
463
+ replace_history_parameter (
464
+ expression, parameter2history, location, mode, history, ID_old);
449
465
450
466
// Create instructions corresponding to the ensures clause
451
467
goto_programt ensures_program;
0 commit comments