13
13
14
14
#include < util/c_types.h>
15
15
#include < util/format_expr.h>
16
+ #include < util/mathematical_expr.h>
16
17
#include < util/pointer_predicates.h>
17
18
#include < util/prefix.h>
18
19
#include < util/replace_symbol.h>
26
27
27
28
#define MAX_TEXT 20
28
29
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
+
29
47
static std::string expr2text (const exprt &src, const namespacet &ns)
30
48
{
31
49
auto text = expr2c (src, ns);
@@ -120,15 +138,22 @@ exprt assigns_match(const exprt &assigns, const exprt &lhs)
120
138
}
121
139
}
122
140
141
+ static exprt instantiate_contract_lambda (exprt src)
142
+ {
143
+ return src.id () == ID_lambda ? to_lambda_expr (src).where () : src;
144
+ }
145
+
123
146
static exprt make_assigns_assertion (
124
147
irep_idt function_identifier,
125
148
const exprt::operandst &assigns,
126
149
const exprt &lhs)
127
150
{
128
151
exprt::operandst disjuncts;
129
152
130
- for (auto &a : assigns)
153
+ for (auto &assigns_clause : assigns)
131
154
{
155
+ auto a = instantiate_contract_lambda (assigns_clause);
156
+
132
157
if (a.id () == ID_conditional_target_group)
133
158
{
134
159
auto &condition = to_binary_expr (a).op0 ();
@@ -247,8 +272,14 @@ void instrument_contract_checks(
247
272
goto_functionst::function_mapt::value_type &f,
248
273
const namespacet &ns)
249
274
{
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
+
252
283
auto &body = f.second .body ;
253
284
254
285
if (body.instructions .empty ())
@@ -264,7 +295,8 @@ void instrument_contract_checks(
264
295
goto_programt dest;
265
296
for (auto &assumption : contract.requires ())
266
297
{
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);
268
300
add_at_beginning.add (goto_programt::make_assumption (
269
301
fixed_assumption, fixed_assumption.source_location ()));
270
302
}
@@ -284,16 +316,19 @@ void instrument_contract_checks(
284
316
285
317
for (auto &assertion : contract.ensures ())
286
318
{
319
+ exprt assertion_instance = instantiate_contract_lambda (assertion);
320
+
287
321
std::string comment = " postcondition" ;
288
322
if (contract.ensures ().size () >= 2 )
289
- comment += " " + expr2text (assertion , ns);
323
+ comment += " " + expr2text (assertion_instance , ns);
290
324
291
325
auto location = assertion.source_location ();
292
326
location.set_function (f.first ); // seems to be missing
293
327
location.set_property_class (ID_postcondition);
294
328
location.set_comment (comment);
295
329
296
- auto replaced_assertion = replace_old (assertion, old_prefix, old_exprs);
330
+ auto replaced_assertion =
331
+ replace_old (assertion_instance, old_prefix, old_exprs);
297
332
298
333
auto fixed_assertion = add_function (f.first , replaced_assertion);
299
334
@@ -319,7 +354,7 @@ void instrument_contract_checks(
319
354
// Add assignments to 'old' symbols at the beginning of the function.
320
355
{
321
356
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 ));
323
358
add_at_beginning.destructive_append (tmp);
324
359
}
325
360
@@ -377,14 +412,12 @@ void replace_function_calls_by_contracts(
377
412
{
378
413
const auto &symbol = ns.lookup (to_symbol_expr (function));
379
414
380
- auto &contract = to_code_with_contract_type (symbol.type );
415
+ const auto contract_opt = get_contract (symbol.name , ns );
381
416
382
- if (
383
- contract.requires ().empty () && contract.ensures ().empty () &&
384
- contract.assigns ().empty ())
385
- {
417
+ if (!contract_opt.has_value ())
386
418
continue ;
387
- }
419
+
420
+ auto &contract = contract_opt.value ();
388
421
389
422
// record "old(...)" expressions.
390
423
std::vector<std::pair<symbol_exprt, exprt>> old_exprs;
@@ -394,6 +427,7 @@ void replace_function_calls_by_contracts(
394
427
// need to substitute parameters
395
428
const auto f_it =
396
429
goto_model.goto_functions .function_map .find (symbol.name );
430
+
397
431
if (f_it == goto_model.goto_functions .function_map .end ())
398
432
DATA_INVARIANT (false , " failed to find function in function_map" );
399
433
@@ -419,24 +453,30 @@ void replace_function_calls_by_contracts(
419
453
// assert the preconditions
420
454
for (auto &precondition : contract.requires ())
421
455
{
456
+ auto instantiated_precondition =
457
+ instantiate_contract_lambda (precondition);
458
+
422
459
auto location = it->source_location ();
423
460
location.set_property_class (ID_precondition);
424
461
location.set_comment (
425
462
id2string (symbol.display_name ()) + " precondition " +
426
- expr2text (precondition , ns));
463
+ expr2text (instantiated_precondition , ns));
427
464
428
- auto replaced_precondition = precondition ;
465
+ auto replaced_precondition = instantiated_precondition ;
429
466
replace_symbol (replaced_precondition);
430
467
431
468
dest.add (
432
469
goto_programt::make_assertion (replaced_precondition, location));
433
470
}
434
471
435
472
// havoc the 'assigned' variables
436
- for (auto &assigns_clause : contract.assigns ())
473
+ for (auto &assigns_clause_lambda : contract.assigns ())
437
474
{
438
475
auto location = it->source_location ();
439
476
477
+ auto assigns_clause =
478
+ instantiate_contract_lambda (assigns_clause_lambda);
479
+
440
480
if (assigns_clause.id () == ID_conditional_target_group)
441
481
{
442
482
const auto &condition = to_binary_expr (assigns_clause).op0 ();
@@ -486,7 +526,8 @@ void replace_function_calls_by_contracts(
486
526
{
487
527
auto &location = it->source_location ();
488
528
489
- auto replaced_postcondition1 = postcondition;
529
+ auto replaced_postcondition1 =
530
+ instantiate_contract_lambda (postcondition);
490
531
replace_symbol (replaced_postcondition1);
491
532
492
533
auto replaced_postcondition2 =
0 commit comments