Skip to content

Commit 627d81f

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 c2f711b commit 627d81f

File tree

3 files changed

+77
-64
lines changed

3 files changed

+77
-64
lines changed

src/goto-instrument/code_contracts.cpp

Lines changed: 63 additions & 59 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 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);

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.

src/util/c_types.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,10 @@ class code_with_contract_typet : public code_typet
352352

353353
exprt &assigns()
354354
{
355-
return static_cast<exprt &>(add(ID_C_spec_assigns));
355+
auto &result = static_cast<exprt &>(add(ID_C_spec_assigns));
356+
if(result.id().empty()) // not initialized?
357+
result.make_nil();
358+
return result;
356359
}
357360

358361
const exprt &requires() const
@@ -362,7 +365,10 @@ class code_with_contract_typet : public code_typet
362365

363366
exprt &requires()
364367
{
365-
return static_cast<exprt &>(add(ID_C_spec_requires));
368+
auto &result = static_cast<exprt &>(add(ID_C_spec_requires));
369+
if(result.id().empty()) // not initialized?
370+
result.make_nil();
371+
return result;
366372
}
367373

368374
const exprt &ensures() const
@@ -372,7 +378,10 @@ class code_with_contract_typet : public code_typet
372378

373379
exprt &ensures()
374380
{
375-
return static_cast<exprt &>(add(ID_C_spec_ensures));
381+
auto &result = static_cast<exprt &>(add(ID_C_spec_ensures));
382+
if(result.id().empty()) // not initialized?
383+
result.make_nil();
384+
return result;
376385
}
377386
};
378387

0 commit comments

Comments
 (0)