@@ -172,9 +172,9 @@ bool code_contractst::has_contract(const irep_idt fun_name)
172
172
}
173
173
174
174
void code_contractst::add_quantified_variable (
175
- exprt expression,
175
+ const exprt & expression,
176
176
replace_symbolt &replace,
177
- irep_idt mode)
177
+ const irep_idt & mode)
178
178
{
179
179
if (expression.id () == ID_not || expression.id () == ID_typecast)
180
180
{
@@ -213,15 +213,13 @@ void code_contractst::add_quantified_variable(
213
213
else if (expression.id () == ID_exists || expression.id () == ID_forall)
214
214
{
215
215
// When a quantifier expression is found,
216
- // 1. get quantified variables
216
+ // for each quantified variable ...
217
217
const auto &quantifier_expression = to_quantifier_expr (expression);
218
- const auto &quantified_variables = quantifier_expression.variables ();
219
- for (const auto &quantified_variable : quantified_variables)
218
+ for (const auto &quantified_variable : quantifier_expression.variables ())
220
219
{
221
- // for each quantified variable...
222
220
const auto &quantified_symbol = to_symbol_expr (quantified_variable);
223
221
224
- // 1.1 create fresh symbol
222
+ // 1. create fresh symbol
225
223
symbolt new_symbol = get_fresh_aux_symbol (
226
224
quantified_symbol.type (),
227
225
id2string (quantified_symbol.get_identifier ()),
@@ -230,12 +228,12 @@ void code_contractst::add_quantified_variable(
230
228
mode,
231
229
symbol_table);
232
230
233
- // 1.2 add created fresh symbol to expression map
231
+ // 2. add created fresh symbol to expression map
234
232
symbol_exprt q (
235
233
quantified_symbol.get_identifier (), quantified_symbol.type ());
236
234
replace.insert (q, new_symbol.symbol_expr ());
237
235
238
- // 1.3 recursively check for nested quantified formulae
236
+ // 3. recursively check for nested quantified formulae
239
237
add_quantified_variable (quantifier_expression.where (), replace, mode);
240
238
}
241
239
}
@@ -356,7 +354,8 @@ bool code_contractst::apply_function_contract(
356
354
357
355
// Create a replace_symbolt object, for replacing expressions in the callee
358
356
// with expressions from the call site (e.g. the return value).
359
- replace_symbolt replace;
357
+ // This object tracks replacements that are common to ENSURES and REQUIRES.
358
+ replace_symbolt common_replace;
360
359
if (type.return_type () != empty_typet ())
361
360
{
362
361
// Check whether the function's return value is not disregarded.
@@ -367,7 +366,7 @@ bool code_contractst::apply_function_contract(
367
366
// rewrite calls to foo as follows:
368
367
// x = foo() -> assume(__CPROVER_return_value > 5) -> assume(x > 5)
369
368
symbol_exprt ret_val (CPROVER_PREFIX " return_value" , call.lhs ().type ());
370
- replace .insert (ret_val, call.lhs ());
369
+ common_replace .insert (ret_val, call.lhs ());
371
370
}
372
371
else
373
372
{
@@ -388,38 +387,37 @@ bool code_contractst::apply_function_contract(
388
387
ns,
389
388
symbol_table);
390
389
symbol_exprt ret_val (CPROVER_PREFIX " return_value" , type.return_type ());
391
- replace .insert (ret_val, fresh.symbol_expr ());
390
+ common_replace .insert (ret_val, fresh.symbol_expr ());
392
391
}
393
392
}
394
393
}
395
394
396
395
// Replace formal parameters
397
- code_function_callt::argumentst::const_iterator a_it=
398
- call.arguments ().begin ();
399
- for (code_typet::parameterst::const_iterator p_it = type.parameters ().begin ();
396
+ auto a_it = call.arguments ().begin ();
397
+ for (auto p_it = type.parameters ().begin ();
400
398
p_it != type.parameters ().end () && a_it != call.arguments ().end ();
401
399
++p_it, ++a_it)
402
400
{
403
401
if (!p_it->get_identifier ().empty ())
404
402
{
405
403
symbol_exprt p (p_it->get_identifier (), p_it->type ());
406
- replace .insert (p, *a_it);
404
+ common_replace .insert (p, *a_it);
407
405
}
408
406
}
409
407
410
- // Add quantified variables in contracts to the symbol map
411
- irep_idt mode = symbol_table.lookup_ref (function).mode ;
412
- code_contractst::add_quantified_variable (ensures, replace, mode);
413
- code_contractst::add_quantified_variable (requires , replace, mode);
408
+ // ASSIGNS clause should not refer to any quantified variables,
409
+ // and only refer to the common symbols to be replaced.
410
+ common_replace (assigns);
414
411
415
- // Replace expressions in the contract components.
416
- replace (assigns);
417
- replace (requires );
418
- replace (ensures);
412
+ const auto &mode = symbol_table.lookup_ref (function).mode ;
419
413
420
414
// Insert assertion of the precondition immediately before the call site.
421
415
if (requires .is_not_nil ())
422
416
{
417
+ replace_symbolt replace (common_replace);
418
+ code_contractst::add_quantified_variable (requires , replace, mode);
419
+ replace (requires );
420
+
423
421
goto_programt assertion;
424
422
converter.goto_convert (
425
423
code_assertt (requires ),
@@ -435,6 +433,10 @@ bool code_contractst::apply_function_contract(
435
433
std::pair<goto_programt, goto_programt> ensures_pair;
436
434
if (ensures.is_not_nil ())
437
435
{
436
+ replace_symbolt replace (common_replace);
437
+ code_contractst::add_quantified_variable (ensures, replace, mode);
438
+ replace (ensures);
439
+
438
440
auto assumption = code_assumet (ensures);
439
441
ensures_pair = create_ensures_instruction (
440
442
assumption,
@@ -616,26 +618,22 @@ void code_contractst::instrument_call_statement(
616
618
617
619
exprt called_assigns =
618
620
to_code_with_contract_type (called_symbol.type ).assigns ();
619
- if (!called_assigns.is_nil ()) // Called function has assigns clause
620
- {
621
- replace_symbolt replace;
622
- // Replace formal parameters
623
- code_function_callt::argumentst::const_iterator a_it =
624
- call.arguments ().begin ();
625
- for (code_typet::parameterst::const_iterator p_it =
626
- called_type.parameters ().begin ();
621
+ if (called_assigns.is_not_nil ())
622
+ {
623
+ replace_symbolt replace_formal_params;
624
+ auto a_it = call.arguments ().begin ();
625
+ for (auto p_it = called_type.parameters ().begin ();
627
626
p_it != called_type.parameters ().end () &&
628
627
a_it != call.arguments ().end ();
629
628
++p_it, ++a_it)
630
629
{
631
630
if (!p_it->get_identifier ().empty ())
632
631
{
633
632
symbol_exprt p (p_it->get_identifier (), p_it->type ());
634
- replace .insert (p, *a_it);
633
+ replace_formal_params .insert (p, *a_it);
635
634
}
636
635
}
637
-
638
- replace (called_assigns);
636
+ replace_formal_params (called_assigns);
639
637
640
638
// check compatibility of assigns clause with the called function
641
639
assigns_clauset called_assigns_clause (
@@ -876,11 +874,12 @@ void code_contractst::add_contract_check(
876
874
PRECONDITION (!dest.instructions .empty ());
877
875
878
876
const symbolt &function_symbol = ns.lookup (mangled_fun);
879
- const auto &code_type = to_code_with_contract_type (function_symbol.type );
877
+ auto code_type = to_code_with_contract_type (function_symbol.type );
878
+
879
+ exprt &assigns = code_type.assigns ();
880
+ exprt &requires = code_type.requires ();
881
+ exprt &ensures = code_type.ensures ();
880
882
881
- const exprt &assigns = code_type.assigns ();
882
- const exprt &requires = code_type.requires ();
883
- const exprt &ensures = code_type.ensures ();
884
883
INVARIANT (
885
884
ensures.is_not_nil () || assigns.is_not_nil (),
886
885
" Code contract enforcement is trivial without an ensures or assigns "
@@ -905,7 +904,11 @@ void code_contractst::add_contract_check(
905
904
906
905
// prepare function call including all declarations
907
906
code_function_callt call (function_symbol.symbol_expr ());
908
- replace_symbolt replace;
907
+
908
+ // Create a replace_symbolt object, for replacing expressions in the callee
909
+ // with expressions from the call site (e.g. the return value).
910
+ // This object tracks replacements that are common to ENSURES and REQUIRES.
911
+ replace_symbolt common_replace;
909
912
910
913
// decl ret
911
914
code_returnt return_stmt;
@@ -923,7 +926,7 @@ void code_contractst::add_contract_check(
923
926
return_stmt = code_returnt (r);
924
927
925
928
symbol_exprt ret_val (CPROVER_PREFIX " return_value" , call.lhs ().type ());
926
- replace .insert (ret_val, r);
929
+ common_replace .insert (ret_val, r);
927
930
}
928
931
929
932
// decl parameter1 ...
@@ -948,39 +951,40 @@ void code_contractst::add_contract_check(
948
951
949
952
call.arguments ().push_back (p);
950
953
951
- replace .insert (parameter_symbol.symbol_expr (), p);
954
+ common_replace .insert (parameter_symbol.symbol_expr (), p);
952
955
}
953
956
954
- // Add quantified variables in contracts to the symbol map
955
- code_contractst::add_quantified_variable (
956
- ensures, replace, function_symbol.mode );
957
- code_contractst::add_quantified_variable (
958
- requires , replace, function_symbol.mode );
959
-
960
- // rewrite any use of __CPROVER_return_value
961
- exprt ensures_cond = ensures;
962
- replace (ensures_cond);
963
-
964
- // assume(requires)
957
+ // generate: assume(requires)
965
958
if (requires .is_not_nil ())
966
959
{
967
- // rewrite any use of parameters
968
- exprt requires_cond = requires ;
969
- replace (requires_cond);
960
+ // extend common_replace with quantified variables in REQUIRES,
961
+ // and then do the replacement
962
+ replace_symbolt replace (common_replace);
963
+ code_contractst::add_quantified_variable (
964
+ requires , replace, function_symbol.mode );
965
+ replace (requires );
970
966
971
967
goto_programt assumption;
972
968
converter.goto_convert (
973
- code_assumet (requires_cond ), assumption, function_symbol.mode );
969
+ code_assumet (requires ), assumption, function_symbol.mode );
974
970
check.destructive_append (assumption);
975
971
}
976
972
977
973
// Prepare the history variables handling
978
974
std::pair<goto_programt, goto_programt> ensures_pair;
979
975
976
+ // generate: assert(ensures)
980
977
if (ensures.is_not_nil ())
981
978
{
979
+ // extend common_replace with quantified variables in ENSURES,
980
+ // and then do the replacement
981
+ replace_symbolt replace (common_replace);
982
+ code_contractst::add_quantified_variable (
983
+ ensures, replace, function_symbol.mode );
984
+ replace (ensures);
985
+
982
986
// get all the relevant instructions related to history variables
983
- auto assertion = code_assertt (ensures_cond );
987
+ auto assertion = code_assertt (ensures );
984
988
ensures_pair = create_ensures_instruction (
985
989
assertion, ensures.source_location (), wrapper_fun, function_symbol.mode );
986
990
0 commit comments