1313
1414#include < util/c_types.h>
1515#include < util/format_expr.h>
16+ #include < util/mathematical_expr.h>
1617#include < util/pointer_predicates.h>
1718#include < util/prefix.h>
1819#include < util/replace_symbol.h>
2627
2728#define MAX_TEXT 20
2829
30+ optionalt<code_with_contract_typet>
31+ get_contract (const irep_idt &function_identifier, const namespacet &ns)
32+ {
33+ // contracts are in a separate symbol, with prefix "contract::"
34+ auto contract_identifier = " contract::" + id2string (function_identifier);
35+ const symbolt *symbol_ptr;
36+ if (ns.lookup (contract_identifier, symbol_ptr))
37+ return {}; // symbol not found
38+ else
39+ return to_code_with_contract_type (symbol_ptr->type );
40+ }
41+
42+ bool has_contract (const irep_idt &function_identifier, const namespacet &ns)
43+ {
44+ return get_contract (function_identifier, ns).has_value ();
45+ }
46+
2947static std::string expr2text (const exprt &src, const namespacet &ns)
3048{
3149 auto text = expr2c (src, ns);
@@ -120,15 +138,22 @@ exprt assigns_match(const exprt &assigns, const exprt &lhs)
120138 }
121139}
122140
141+ static exprt instantiate_contract_lambda (exprt src)
142+ {
143+ return src.id () == ID_lambda ? to_lambda_expr (src).where () : src;
144+ }
145+
123146static exprt make_assigns_assertion (
124147 irep_idt function_identifier,
125148 const exprt::operandst &assigns,
126149 const exprt &lhs)
127150{
128151 exprt::operandst disjuncts;
129152
130- for (auto &a : assigns)
153+ for (auto &assigns_clause : assigns)
131154 {
155+ auto a = instantiate_contract_lambda (assigns_clause);
156+
132157 if (a.id () == ID_conditional_target_group)
133158 {
134159 auto &condition = to_binary_expr (a).op0 ();
@@ -247,8 +272,14 @@ void instrument_contract_checks(
247272 goto_functionst::function_mapt::value_type &f,
248273 const namespacet &ns)
249274{
250- auto &symbol = ns.lookup (f.first );
251- auto &contract = to_code_with_contract_type (symbol.type );
275+ // contracts are in a separate symbol, with prefix "contract::"
276+ auto contract_identifier = " contract::" + id2string (f.first );
277+ const symbolt *symbol_ptr;
278+ if (ns.lookup (contract_identifier, symbol_ptr))
279+ return ; // nothing to check
280+
281+ auto &contract = to_code_with_contract_type (symbol_ptr->type );
282+
252283 auto &body = f.second .body ;
253284
254285 if (body.instructions .empty ())
@@ -264,7 +295,8 @@ void instrument_contract_checks(
264295 goto_programt dest;
265296 for (auto &assumption : contract.requires ())
266297 {
267- auto fixed_assumption = add_function (f.first , assumption);
298+ exprt assumption_instance = instantiate_contract_lambda (assumption);
299+ auto fixed_assumption = add_function (f.first , assumption_instance);
268300 add_at_beginning.add (goto_programt::make_assumption (
269301 fixed_assumption, fixed_assumption.source_location ()));
270302 }
@@ -284,16 +316,19 @@ void instrument_contract_checks(
284316
285317 for (auto &assertion : contract.ensures ())
286318 {
319+ exprt assertion_instance = instantiate_contract_lambda (assertion);
320+
287321 std::string comment = " postcondition" ;
288322 if (contract.ensures ().size () >= 2 )
289- comment += " " + expr2text (assertion , ns);
323+ comment += " " + expr2text (assertion_instance , ns);
290324
291325 auto location = assertion.source_location ();
292326 location.set_function (f.first ); // seems to be missing
293327 location.set_property_class (ID_postcondition);
294328 location.set_comment (comment);
295329
296- auto replaced_assertion = replace_old (assertion, old_prefix, old_exprs);
330+ auto replaced_assertion =
331+ replace_old (assertion_instance, old_prefix, old_exprs);
297332
298333 auto fixed_assertion = add_function (f.first , replaced_assertion);
299334
@@ -319,7 +354,7 @@ void instrument_contract_checks(
319354 // Add assignments to 'old' symbols at the beginning of the function.
320355 {
321356 auto tmp =
322- old_assignments (old_exprs, add_function (f.first , symbol. location ));
357+ old_assignments (old_exprs, add_function (f.first , symbol_ptr-> location ));
323358 add_at_beginning.destructive_append (tmp);
324359 }
325360
@@ -377,14 +412,12 @@ void replace_function_calls_by_contracts(
377412 {
378413 const auto &symbol = ns.lookup (to_symbol_expr (function));
379414
380- auto &contract = to_code_with_contract_type (symbol.type );
415+ const auto contract_opt = get_contract (symbol.name , ns );
381416
382- if (
383- contract.requires ().empty () && contract.ensures ().empty () &&
384- contract.assigns ().empty ())
385- {
417+ if (!contract_opt.has_value ())
386418 continue ;
387- }
419+
420+ auto &contract = contract_opt.value ();
388421
389422 // record "old(...)" expressions.
390423 std::vector<std::pair<symbol_exprt, exprt>> old_exprs;
@@ -394,6 +427,7 @@ void replace_function_calls_by_contracts(
394427 // need to substitute parameters
395428 const auto f_it =
396429 goto_model.goto_functions .function_map .find (symbol.name );
430+
397431 if (f_it == goto_model.goto_functions .function_map .end ())
398432 DATA_INVARIANT (false , " failed to find function in function_map" );
399433
@@ -419,24 +453,30 @@ void replace_function_calls_by_contracts(
419453 // assert the preconditions
420454 for (auto &precondition : contract.requires ())
421455 {
456+ auto instantiated_precondition =
457+ instantiate_contract_lambda (precondition);
458+
422459 auto location = it->source_location ();
423460 location.set_property_class (ID_precondition);
424461 location.set_comment (
425462 id2string (symbol.display_name ()) + " precondition " +
426- expr2text (precondition , ns));
463+ expr2text (instantiated_precondition , ns));
427464
428- auto replaced_precondition = precondition ;
465+ auto replaced_precondition = instantiated_precondition ;
429466 replace_symbol (replaced_precondition);
430467
431468 dest.add (
432469 goto_programt::make_assertion (replaced_precondition, location));
433470 }
434471
435472 // havoc the 'assigned' variables
436- for (auto &assigns_clause : contract.assigns ())
473+ for (auto &assigns_clause_lambda : contract.assigns ())
437474 {
438475 auto location = it->source_location ();
439476
477+ auto assigns_clause =
478+ instantiate_contract_lambda (assigns_clause_lambda);
479+
440480 if (assigns_clause.id () == ID_conditional_target_group)
441481 {
442482 const auto &condition = to_binary_expr (assigns_clause).op0 ();
@@ -486,7 +526,8 @@ void replace_function_calls_by_contracts(
486526 {
487527 auto &location = it->source_location ();
488528
489- auto replaced_postcondition1 = postcondition;
529+ auto replaced_postcondition1 =
530+ instantiate_contract_lambda (postcondition);
490531 replace_symbol (replaced_postcondition1);
491532
492533 auto replaced_postcondition2 =
0 commit comments