Skip to content

Commit 2c2a878

Browse files
committed
Refactor and cleanup
We do not need to do quantifier replacement within ASSIGNS annotation. The replacement maps for ENSURES and REQUIRES clauses should also be maintained independently.
1 parent 1c1fb76 commit 2c2a878

File tree

2 files changed

+59
-55
lines changed

2 files changed

+59
-55
lines changed

src/goto-instrument/code_contracts.cpp

Lines changed: 57 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ bool code_contractst::has_contract(const irep_idt fun_name)
172172
}
173173

174174
void 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 both 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,7 +387,7 @@ 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
}
@@ -403,23 +402,23 @@ bool code_contractst::apply_function_contract(
403402
if(!p_it->get_identifier().empty())
404403
{
405404
symbol_exprt p(p_it->get_identifier(), p_it->type());
406-
replace.insert(p, *a_it);
405+
common_replace.insert(p, *a_it);
407406
}
408407
}
409408

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);
414412

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;
419414

420415
// Insert assertion of the precondition immediately before the call site.
421416
if(requires.is_not_nil())
422417
{
418+
replace_symbolt replace(common_replace);
419+
code_contractst::add_quantified_variable(requires, replace, mode);
420+
replace(requires);
421+
423422
goto_programt assertion;
424423
converter.goto_convert(
425424
code_assertt(requires),
@@ -435,6 +434,10 @@ bool code_contractst::apply_function_contract(
435434
std::pair<goto_programt, goto_programt> ensures_pair;
436435
if(ensures.is_not_nil())
437436
{
437+
replace_symbolt replace(common_replace);
438+
code_contractst::add_quantified_variable(ensures, replace, mode);
439+
replace(ensures);
440+
438441
auto assumption = code_assumet(ensures);
439442
ensures_pair = create_ensures_instruction(
440443
assumption,
@@ -618,24 +621,20 @@ void code_contractst::instrument_call_statement(
618621
to_code_with_contract_type(called_symbol.type).assigns();
619622
if(!called_assigns.is_nil()) // Called function has assigns clause
620623
{
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();
627627
p_it != called_type.parameters().end() &&
628628
a_it != call.arguments().end();
629629
++p_it, ++a_it)
630630
{
631631
if(!p_it->get_identifier().empty())
632632
{
633633
symbol_exprt p(p_it->get_identifier(), p_it->type());
634-
replace.insert(p, *a_it);
634+
replace_formal_params.insert(p, *a_it);
635635
}
636636
}
637-
638-
replace(called_assigns);
637+
replace_formal_params(called_assigns);
639638

640639
// check compatibility of assigns clause with the called function
641640
assigns_clauset called_assigns_clause(
@@ -876,11 +875,12 @@ void code_contractst::add_contract_check(
876875
PRECONDITION(!dest.instructions.empty());
877876

878877
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();
880883

881-
const exprt &assigns = code_type.assigns();
882-
const exprt &requires = code_type.requires();
883-
const exprt &ensures = code_type.ensures();
884884
INVARIANT(
885885
ensures.is_not_nil() || assigns.is_not_nil(),
886886
"Code contract enforcement is trivial without an ensures or assigns "
@@ -905,7 +905,11 @@ void code_contractst::add_contract_check(
905905

906906
// prepare function call including all declarations
907907
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;
909913

910914
// decl ret
911915
code_returnt return_stmt;
@@ -923,7 +927,7 @@ void code_contractst::add_contract_check(
923927
return_stmt = code_returnt(r);
924928

925929
symbol_exprt ret_val(CPROVER_PREFIX "return_value", call.lhs().type());
926-
replace.insert(ret_val, r);
930+
common_replace.insert(ret_val, r);
927931
}
928932

929933
// decl parameter1 ...
@@ -948,29 +952,22 @@ void code_contractst::add_contract_check(
948952

949953
call.arguments().push_back(p);
950954

951-
replace.insert(parameter_symbol.symbol_expr(), p);
955+
common_replace.insert(parameter_symbol.symbol_expr(), p);
952956
}
953957

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)
965959
if(requires.is_not_nil())
966960
{
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);
970967

971968
goto_programt assumption;
972969
converter.goto_convert(
973-
code_assumet(requires_cond), assumption, function_symbol.mode);
970+
code_assumet(requires), assumption, function_symbol.mode);
974971
check.destructive_append(assumption);
975972
}
976973

@@ -979,8 +976,15 @@ void code_contractst::add_contract_check(
979976

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

src/goto-instrument/code_contracts.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ class code_contractst
185185
/// the quantified variable is added to the symbol table
186186
/// and to the expression map.
187187
void add_quantified_variable(
188-
exprt expression,
188+
const exprt &expression,
189189
replace_symbolt &replace,
190-
irep_idt mode);
190+
const irep_idt &mode);
191191

192192
/// This function recursively identifies the "old" expressions within expr
193193
/// and replaces them with correspoding history variables.

0 commit comments

Comments
 (0)