@@ -172,9 +172,9 @@ bool code_contractst::has_contract(const irep_idt fun_name)
172172}
173173
174174void code_contractst::add_quantified_variable (
175- exprt expression,
175+ const exprt & expression,
176176 replace_symbolt &replace,
177- irep_idt mode)
177+ const irep_idt & mode)
178178{
179179 if (expression.id () == ID_not || expression.id () == ID_typecast)
180180 {
@@ -213,15 +213,13 @@ void code_contractst::add_quantified_variable(
213213 else if (expression.id () == ID_exists || expression.id () == ID_forall)
214214 {
215215 // When a quantifier expression is found,
216- // 1. get quantified variables
216+ // for each quantified variable ...
217217 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 ())
220219 {
221- // for each quantified variable...
222220 const auto &quantified_symbol = to_symbol_expr (quantified_variable);
223221
224- // 1.1 create fresh symbol
222+ // 1. create fresh symbol
225223 symbolt new_symbol = get_fresh_aux_symbol (
226224 quantified_symbol.type (),
227225 id2string (quantified_symbol.get_identifier ()),
@@ -230,12 +228,12 @@ void code_contractst::add_quantified_variable(
230228 mode,
231229 symbol_table);
232230
233- // 1.2 add created fresh symbol to expression map
231+ // 2. add created fresh symbol to expression map
234232 symbol_exprt q (
235233 quantified_symbol.get_identifier (), quantified_symbol.type ());
236234 replace.insert (q, new_symbol.symbol_expr ());
237235
238- // 1.3 recursively check for nested quantified formulae
236+ // 3. recursively check for nested quantified formulae
239237 add_quantified_variable (quantifier_expression.where (), replace, mode);
240238 }
241239 }
@@ -356,7 +354,8 @@ bool code_contractst::apply_function_contract(
356354
357355 // Create a replace_symbolt object, for replacing expressions in the callee
358356 // 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;
360359 if (type.return_type () != empty_typet ())
361360 {
362361 // Check whether the function's return value is not disregarded.
@@ -367,7 +366,7 @@ bool code_contractst::apply_function_contract(
367366 // rewrite calls to foo as follows:
368367 // x = foo() -> assume(__CPROVER_return_value > 5) -> assume(x > 5)
369368 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 ());
371370 }
372371 else
373372 {
@@ -388,38 +387,37 @@ bool code_contractst::apply_function_contract(
388387 ns,
389388 symbol_table);
390389 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 ());
392391 }
393392 }
394393 }
395394
396395 // 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 ();
400398 p_it != type.parameters ().end () && a_it != call.arguments ().end ();
401399 ++p_it, ++a_it)
402400 {
403401 if (!p_it->get_identifier ().empty ())
404402 {
405403 symbol_exprt p (p_it->get_identifier (), p_it->type ());
406- replace .insert (p, *a_it);
404+ common_replace .insert (p, *a_it);
407405 }
408406 }
409407
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);
414411
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 ;
419413
420414 // Insert assertion of the precondition immediately before the call site.
421415 if (requires .is_not_nil ())
422416 {
417+ replace_symbolt replace (common_replace);
418+ code_contractst::add_quantified_variable (requires , replace, mode);
419+ replace (requires );
420+
423421 goto_programt assertion;
424422 converter.goto_convert (
425423 code_assertt (requires ),
@@ -435,6 +433,10 @@ bool code_contractst::apply_function_contract(
435433 std::pair<goto_programt, goto_programt> ensures_pair;
436434 if (ensures.is_not_nil ())
437435 {
436+ replace_symbolt replace (common_replace);
437+ code_contractst::add_quantified_variable (ensures, replace, mode);
438+ replace (ensures);
439+
438440 auto assumption = code_assumet (ensures);
439441 ensures_pair = create_ensures_instruction (
440442 assumption,
@@ -616,26 +618,22 @@ void code_contractst::instrument_call_statement(
616618
617619 exprt called_assigns =
618620 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 ();
627626 p_it != called_type.parameters ().end () &&
628627 a_it != call.arguments ().end ();
629628 ++p_it, ++a_it)
630629 {
631630 if (!p_it->get_identifier ().empty ())
632631 {
633632 symbol_exprt p (p_it->get_identifier (), p_it->type ());
634- replace .insert (p, *a_it);
633+ replace_formal_params .insert (p, *a_it);
635634 }
636635 }
637-
638- replace (called_assigns);
636+ replace_formal_params (called_assigns);
639637
640638 // check compatibility of assigns clause with the called function
641639 assigns_clauset called_assigns_clause (
@@ -876,11 +874,12 @@ void code_contractst::add_contract_check(
876874 PRECONDITION (!dest.instructions .empty ());
877875
878876 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 ();
880882
881- const exprt &assigns = code_type.assigns ();
882- const exprt &requires = code_type.requires ();
883- const exprt &ensures = code_type.ensures ();
884883 INVARIANT (
885884 ensures.is_not_nil () || assigns.is_not_nil (),
886885 " Code contract enforcement is trivial without an ensures or assigns "
@@ -905,7 +904,11 @@ void code_contractst::add_contract_check(
905904
906905 // prepare function call including all declarations
907906 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;
909912
910913 // decl ret
911914 code_returnt return_stmt;
@@ -923,7 +926,7 @@ void code_contractst::add_contract_check(
923926 return_stmt = code_returnt (r);
924927
925928 symbol_exprt ret_val (CPROVER_PREFIX " return_value" , call.lhs ().type ());
926- replace .insert (ret_val, r);
929+ common_replace .insert (ret_val, r);
927930 }
928931
929932 // decl parameter1 ...
@@ -948,39 +951,40 @@ void code_contractst::add_contract_check(
948951
949952 call.arguments ().push_back (p);
950953
951- replace .insert (parameter_symbol.symbol_expr (), p);
954+ common_replace .insert (parameter_symbol.symbol_expr (), p);
952955 }
953956
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)
965958 if (requires .is_not_nil ())
966959 {
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 );
970966
971967 goto_programt assumption;
972968 converter.goto_convert (
973- code_assumet (requires_cond ), assumption, function_symbol.mode );
969+ code_assumet (requires ), assumption, function_symbol.mode );
974970 check.destructive_append (assumption);
975971 }
976972
977973 // Prepare the history variables handling
978974 std::pair<goto_programt, goto_programt> ensures_pair;
979975
976+ // Generate: copies for history variables
980977 if (ensures.is_not_nil ())
981978 {
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+
982986 // get all the relevant instructions related to history variables
983- auto assertion = code_assertt (ensures_cond );
987+ auto assertion = code_assertt (ensures );
984988 ensures_pair = create_ensures_instruction (
985989 assertion, ensures.source_location (), wrapper_fun, function_symbol.mode );
986990
@@ -991,7 +995,7 @@ void code_contractst::add_contract_check(
991995 // ret=mangled_fun(parameter1, ...)
992996 check.add (goto_programt::make_function_call (call, skip->source_location ));
993997
994- // assert(ensures)
998+ // Generate: assert(ensures)
995999 if (ensures.is_not_nil ())
9961000 {
9971001 check.destructive_append (ensures_pair.first );
0 commit comments