@@ -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 both 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,7 +387,7 @@ 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
}
@@ -403,23 +402,23 @@ bool code_contractst::apply_function_contract(
403
402
if (!p_it->get_identifier ().empty ())
404
403
{
405
404
symbol_exprt p (p_it->get_identifier (), p_it->type ());
406
- replace .insert (p, *a_it);
405
+ common_replace .insert (p, *a_it);
407
406
}
408
407
}
409
408
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);
409
+ // ASSIGNS clause should not refer to any quantified variables,
410
+ // and only refer to the common symbols to be replaced.
411
+ common_replace (assigns);
414
412
415
- // Replace expressions in the contract components.
416
- replace (assigns);
417
- replace (requires );
418
- replace (ensures);
413
+ irep_idt mode = symbol_table.lookup_ref (function).mode ;
419
414
420
415
// Insert assertion of the precondition immediately before the call site.
421
416
if (requires .is_not_nil ())
422
417
{
418
+ replace_symbolt replace (common_replace);
419
+ code_contractst::add_quantified_variable (requires , replace, mode);
420
+ replace (requires );
421
+
423
422
goto_programt assertion;
424
423
converter.goto_convert (
425
424
code_assertt (requires ),
@@ -435,6 +434,10 @@ bool code_contractst::apply_function_contract(
435
434
std::pair<goto_programt, goto_programt> ensures_pair;
436
435
if (ensures.is_not_nil ())
437
436
{
437
+ replace_symbolt replace (common_replace);
438
+ code_contractst::add_quantified_variable (ensures, replace, mode);
439
+ replace (ensures);
440
+
438
441
auto assumption = code_assumet (ensures);
439
442
ensures_pair = create_ensures_instruction (
440
443
assumption,
@@ -618,24 +621,20 @@ void code_contractst::instrument_call_statement(
618
621
to_code_with_contract_type (called_symbol.type ).assigns ();
619
622
if (!called_assigns.is_nil ()) // Called function has assigns clause
620
623
{
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 ();
624
+ replace_symbolt replace_formal_params;
625
+ auto a_it = call.arguments ().begin ();
626
+ for (auto p_it = called_type.parameters ().begin ();
627
627
p_it != called_type.parameters ().end () &&
628
628
a_it != call.arguments ().end ();
629
629
++p_it, ++a_it)
630
630
{
631
631
if (!p_it->get_identifier ().empty ())
632
632
{
633
633
symbol_exprt p (p_it->get_identifier (), p_it->type ());
634
- replace .insert (p, *a_it);
634
+ replace_formal_params .insert (p, *a_it);
635
635
}
636
636
}
637
-
638
- replace (called_assigns);
637
+ replace_formal_params (called_assigns);
639
638
640
639
// check compatibility of assigns clause with the called function
641
640
assigns_clauset called_assigns_clause (
@@ -876,11 +875,12 @@ void code_contractst::add_contract_check(
876
875
PRECONDITION (!dest.instructions .empty ());
877
876
878
877
const symbolt &function_symbol = ns.lookup (mangled_fun);
879
- const auto &code_type = to_code_with_contract_type (function_symbol.type );
878
+ auto code_type = to_code_with_contract_type (function_symbol.type );
879
+
880
+ exprt &assigns = code_type.assigns ();
881
+ exprt &requires = code_type.requires ();
882
+ exprt &ensures = code_type.ensures ();
880
883
881
- const exprt &assigns = code_type.assigns ();
882
- const exprt &requires = code_type.requires ();
883
- const exprt &ensures = code_type.ensures ();
884
884
INVARIANT (
885
885
ensures.is_not_nil () || assigns.is_not_nil (),
886
886
" Code contract enforcement is trivial without an ensures or assigns "
@@ -905,7 +905,11 @@ void code_contractst::add_contract_check(
905
905
906
906
// prepare function call including all declarations
907
907
code_function_callt call (function_symbol.symbol_expr ());
908
- replace_symbolt replace;
908
+
909
+ // Create a replace_symbolt object, for replacing expressions in the callee
910
+ // with expressions from the call site (e.g. the return value).
911
+ // This object tracks replacements that are common to ENSURES and REQUIRES.
912
+ replace_symbolt common_replace;
909
913
910
914
// decl ret
911
915
code_returnt return_stmt;
@@ -923,7 +927,7 @@ void code_contractst::add_contract_check(
923
927
return_stmt = code_returnt (r);
924
928
925
929
symbol_exprt ret_val (CPROVER_PREFIX " return_value" , call.lhs ().type ());
926
- replace .insert (ret_val, r);
930
+ common_replace .insert (ret_val, r);
927
931
}
928
932
929
933
// decl parameter1 ...
@@ -948,29 +952,22 @@ void code_contractst::add_contract_check(
948
952
949
953
call.arguments ().push_back (p);
950
954
951
- replace .insert (parameter_symbol.symbol_expr (), p);
955
+ common_replace .insert (parameter_symbol.symbol_expr (), p);
952
956
}
953
957
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)
958
+ // generate: assume(requires)
965
959
if (requires .is_not_nil ())
966
960
{
967
- // rewrite any use of parameters
968
- exprt requires_cond = requires ;
969
- replace (requires_cond);
961
+ // extend common_replace with quantified variables in REQUIRES,
962
+ // and then do the replacement
963
+ replace_symbolt replace (common_replace);
964
+ code_contractst::add_quantified_variable (
965
+ requires , replace, function_symbol.mode );
966
+ replace (requires );
970
967
971
968
goto_programt assumption;
972
969
converter.goto_convert (
973
- code_assumet (requires_cond ), assumption, function_symbol.mode );
970
+ code_assumet (requires ), assumption, function_symbol.mode );
974
971
check.destructive_append (assumption);
975
972
}
976
973
@@ -979,8 +976,15 @@ void code_contractst::add_contract_check(
979
976
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