@@ -25,7 +25,6 @@ Date: February 2016
25
25
#include < util/message.h>
26
26
#include < util/pointer_offset_size.h>
27
27
#include < util/pointer_predicates.h>
28
- #include < util/replace_symbol.h>
29
28
#include < util/std_code.h>
30
29
31
30
#include < goto-programs/goto_inline.h>
@@ -777,15 +776,12 @@ void code_contractst::apply_function_contract(
777
776
// Isolate each component of the contract.
778
777
const auto &type = get_contract (target_function, ns);
779
778
auto assigns_clause = type.assigns ();
780
- auto requires = conjunction (type.requires ());
781
- auto ensures = conjunction (type.ensures ());
782
779
auto requires_contract = type.requires_contract ();
783
780
auto ensures_contract = type.ensures_contract ();
784
781
785
- // Create a replace_symbolt object, for replacing expressions in the callee
782
+ // Prepare to instantiate expressions in the callee
786
783
// with expressions from the call site (e.g. the return value).
787
- // This object tracks replacements that are common to ENSURES and REQUIRES.
788
- replace_symbolt common_replace;
784
+ exprt::operandst instantiation_values;
789
785
790
786
// keep track of the call's return expression to make it nondet later
791
787
optionalt<exprt> call_ret_opt = {};
@@ -804,17 +800,17 @@ void code_contractst::apply_function_contract(
804
800
// x = foo() -> assume(__CPROVER_return_value > 5) -> assume(x > 5)
805
801
auto &lhs_expr = const_target->call_lhs ();
806
802
call_ret_opt = lhs_expr;
807
- symbol_exprt ret_val (CPROVER_PREFIX " return_value" , lhs_expr.type ());
808
- common_replace.insert (ret_val, lhs_expr);
803
+ instantiation_values.push_back (lhs_expr);
809
804
}
810
805
else
811
806
{
812
807
// If the function does return a value, but the return value is
813
808
// disregarded, check if the postcondition includes the return value.
814
- if (has_subexpr (ensures, [](const exprt &e) {
815
- return e.id () == ID_symbol && to_symbol_expr (e).get_identifier () ==
816
- CPROVER_PREFIX " return_value" ;
817
- }))
809
+ if (std::any_of (
810
+ type.ensures ().begin (), type.ensures ().end (), [](const exprt &e) {
811
+ return has_symbol_expr (
812
+ to_lambda_expr (e).where (), CPROVER_PREFIX " return_value" , true );
813
+ }))
818
814
{
819
815
// The postcondition does mention __CPROVER_return_value, so mint a
820
816
// fresh variable to replace __CPROVER_return_value with.
@@ -827,28 +823,19 @@ void code_contractst::apply_function_contract(
827
823
symbol_table.lookup_ref (target_function).mode ,
828
824
ns,
829
825
symbol_table);
830
- symbol_exprt ret_val (
831
- CPROVER_PREFIX " return_value" , function_type.return_type ());
832
826
auto fresh_sym_expr = fresh.symbol_expr ();
833
- common_replace.insert (ret_val, fresh_sym_expr);
834
827
call_ret_opt = fresh_sym_expr;
828
+ instantiation_values.push_back (fresh_sym_expr);
835
829
}
830
+ else
831
+ instantiation_values.push_back (nil_exprt{});
836
832
}
837
833
}
838
834
839
835
// Replace formal parameters
840
836
const auto &arguments = const_target->call_arguments ();
841
- auto a_it = arguments.begin ();
842
- for (auto p_it = type.parameters ().begin ();
843
- p_it != type.parameters ().end () && a_it != arguments.end ();
844
- ++p_it, ++a_it)
845
- {
846
- if (!p_it->get_identifier ().empty ())
847
- {
848
- symbol_exprt p (p_it->get_identifier (), p_it->type ());
849
- common_replace.insert (p, *a_it);
850
- }
851
- }
837
+ instantiation_values.insert (
838
+ instantiation_values.end (), arguments.begin (), arguments.end ());
852
839
853
840
const auto &mode = function_symbol.mode ;
854
841
@@ -860,11 +847,17 @@ void code_contractst::apply_function_contract(
860
847
is_fresh.add_memory_map_decl (new_program);
861
848
862
849
// Insert assertion of the precondition immediately before the call site.
850
+ exprt::operandst requires_conjuncts;
851
+ for (const auto &r : type.requires ())
852
+ {
853
+ requires_conjuncts.push_back (
854
+ to_lambda_expr (r).application (instantiation_values));
855
+ }
856
+ auto requires = conjunction (requires_conjuncts);
863
857
if (!requires.is_true ())
864
858
{
865
859
if (has_subexpr (requires, ID_exists) || has_subexpr (requires, ID_forall))
866
860
add_quantified_variable (requires, mode);
867
- common_replace (requires);
868
861
869
862
goto_programt assertion;
870
863
converter.goto_convert (code_assertt (requires), assertion, mode);
@@ -882,21 +875,27 @@ void code_contractst::apply_function_contract(
882
875
for (auto &expr : requires_contract)
883
876
{
884
877
assert_function_pointer_obeys_contract (
885
- to_function_pointer_obeys_contract_expr (expr),
878
+ to_function_pointer_obeys_contract_expr (
879
+ to_lambda_expr (expr).application (instantiation_values)),
886
880
ID_precondition,
887
- common_replace,
888
881
mode,
889
882
new_program);
890
883
}
891
884
892
885
// Gather all the instructions required to handle history variables
893
886
// as well as the ensures clause
887
+ exprt::operandst ensures_conjuncts;
888
+ for (const auto &r : type.ensures ())
889
+ {
890
+ ensures_conjuncts.push_back (
891
+ to_lambda_expr (r).application (instantiation_values));
892
+ }
893
+ auto ensures = conjunction (ensures_conjuncts);
894
894
std::pair<goto_programt, goto_programt> ensures_pair;
895
895
if (!ensures.is_false ())
896
896
{
897
897
if (has_subexpr (ensures, ID_exists) || has_subexpr (ensures, ID_forall))
898
898
add_quantified_variable (ensures, mode);
899
- common_replace (ensures);
900
899
901
900
auto assumption = code_assumet (ensures);
902
901
ensures_pair =
@@ -908,10 +907,9 @@ void code_contractst::apply_function_contract(
908
907
909
908
// ASSIGNS clause should not refer to any quantified variables,
910
909
// and only refer to the common symbols to be replaced.
911
- exprt targets;
910
+ exprt::operandst targets;
912
911
for (auto &target : assigns_clause)
913
- targets.add_to_operands (std::move (target));
914
- common_replace (targets);
912
+ targets.push_back (to_lambda_expr (target).application (instantiation_values));
915
913
916
914
// Create a sequence of non-deterministic assignments ...
917
915
@@ -920,7 +918,7 @@ void code_contractst::apply_function_contract(
920
918
921
919
havoc_assigns_clause_targetst havocker (
922
920
target_function,
923
- targets. operands () ,
921
+ targets,
924
922
goto_functions,
925
923
location,
926
924
symbol_table,
@@ -961,8 +959,8 @@ void code_contractst::apply_function_contract(
961
959
for (auto &expr : ensures_contract)
962
960
{
963
961
assume_function_pointer_obeys_contract (
964
- to_function_pointer_obeys_contract_expr (expr),
965
- common_replace ,
962
+ to_function_pointer_obeys_contract_expr (
963
+ to_lambda_expr (expr). application (instantiation_values)) ,
966
964
mode,
967
965
new_program);
968
966
}
@@ -1399,7 +1397,6 @@ void code_contractst::enforce_contract(const irep_idt &function)
1399
1397
void code_contractst::assert_function_pointer_obeys_contract (
1400
1398
const function_pointer_obeys_contract_exprt &expr,
1401
1399
const irep_idt &property_class,
1402
- const replace_symbolt &replace,
1403
1400
const irep_idt &mode,
1404
1401
goto_programt &dest)
1405
1402
{
@@ -1411,9 +1408,8 @@ void code_contractst::assert_function_pointer_obeys_contract(
1411
1408
<< " ' obeys contract '"
1412
1409
<< from_expr_using_mode (ns, mode, expr.contract ()) << " '" ;
1413
1410
loc.set_comment (comment.str ());
1414
- exprt function_pointer (expr.function_pointer ());
1415
- replace (function_pointer);
1416
- code_assertt assert_expr (equal_exprt{function_pointer, expr.contract ()});
1411
+ code_assertt assert_expr (
1412
+ equal_exprt{expr.function_pointer (), expr.contract ()});
1417
1413
assert_expr.add_source_location () = loc;
1418
1414
goto_programt instructions;
1419
1415
converter.goto_convert (assert_expr, instructions, mode);
@@ -1422,7 +1418,6 @@ void code_contractst::assert_function_pointer_obeys_contract(
1422
1418
1423
1419
void code_contractst::assume_function_pointer_obeys_contract (
1424
1420
const function_pointer_obeys_contract_exprt &expr,
1425
- const replace_symbolt &replace,
1426
1421
const irep_idt &mode,
1427
1422
goto_programt &dest)
1428
1423
{
@@ -1433,10 +1428,8 @@ void code_contractst::assume_function_pointer_obeys_contract(
1433
1428
<< " ' obeys contract '"
1434
1429
<< from_expr_using_mode (ns, mode, expr.contract ()) << " '" ;
1435
1430
loc.set_comment (comment.str ());
1436
- exprt function_pointer (expr.function_pointer ());
1437
- replace (function_pointer);
1438
- dest.add (
1439
- goto_programt::make_assignment (function_pointer, expr.contract (), loc));
1431
+ dest.add (goto_programt::make_assignment (
1432
+ expr.function_pointer (), expr.contract (), loc));
1440
1433
}
1441
1434
1442
1435
void code_contractst::add_contract_check (
@@ -1448,8 +1441,6 @@ void code_contractst::add_contract_check(
1448
1441
1449
1442
const auto &code_type = get_contract (wrapper_function, ns);
1450
1443
auto assigns = code_type.assigns ();
1451
- auto requires = conjunction (code_type.requires ());
1452
- auto ensures = conjunction (code_type.ensures ());
1453
1444
auto requires_contract = code_type.requires_contract ();
1454
1445
auto ensures_contract = code_type.ensures_contract ();
1455
1446
// build:
@@ -1468,10 +1459,9 @@ void code_contractst::add_contract_check(
1468
1459
const symbolt &function_symbol = ns.lookup (mangled_function);
1469
1460
code_function_callt call (function_symbol.symbol_expr ());
1470
1461
1471
- // Create a replace_symbolt object, for replacing expressions in the callee
1462
+ // Prepare to instantiate expressions in the callee
1472
1463
// with expressions from the call site (e.g. the return value).
1473
- // This object tracks replacements that are common to ENSURES and REQUIRES.
1474
- replace_symbolt common_replace;
1464
+ exprt::operandst instantiation_values;
1475
1465
1476
1466
const auto &source_location = function_symbol.location ;
1477
1467
@@ -1490,8 +1480,7 @@ void code_contractst::add_contract_check(
1490
1480
call.lhs () = r;
1491
1481
return_stmt = code_returnt (r);
1492
1482
1493
- symbol_exprt ret_val (CPROVER_PREFIX " return_value" , call.lhs ().type ());
1494
- common_replace.insert (ret_val, r);
1483
+ instantiation_values.push_back (r);
1495
1484
}
1496
1485
1497
1486
// decl parameter1 ...
@@ -1516,18 +1505,24 @@ void code_contractst::add_contract_check(
1516
1505
1517
1506
call.arguments ().push_back (p);
1518
1507
1519
- common_replace. insert (parameter_symbol. symbol_expr (), p);
1508
+ instantiation_values. push_back ( p);
1520
1509
}
1521
1510
1522
1511
is_fresh_enforcet visitor (*this , log , wrapper_function);
1523
1512
visitor.create_declarations ();
1524
1513
visitor.add_memory_map_decl (check);
1525
1514
// Generate: assume(requires)
1515
+ exprt::operandst requires_conjuncts;
1516
+ for (const auto &r : code_type.requires ())
1517
+ {
1518
+ requires_conjuncts.push_back (
1519
+ to_lambda_expr (r).application (instantiation_values));
1520
+ }
1521
+ auto requires = conjunction (requires_conjuncts);
1526
1522
if (!requires.is_false ())
1527
1523
{
1528
1524
if (has_subexpr (requires, ID_exists) || has_subexpr (requires, ID_forall))
1529
1525
add_quantified_variable (requires, function_symbol.mode );
1530
- common_replace (requires);
1531
1526
1532
1527
goto_programt assumption;
1533
1528
converter.goto_convert (
@@ -1540,11 +1535,17 @@ void code_contractst::add_contract_check(
1540
1535
std::pair<goto_programt, goto_programt> ensures_pair;
1541
1536
1542
1537
// Generate: copies for history variables
1538
+ exprt::operandst ensures_conjuncts;
1539
+ for (const auto &r : code_type.ensures ())
1540
+ {
1541
+ ensures_conjuncts.push_back (
1542
+ to_lambda_expr (r).application (instantiation_values));
1543
+ }
1544
+ auto ensures = conjunction (ensures_conjuncts);
1543
1545
if (!ensures.is_true ())
1544
1546
{
1545
1547
if (has_subexpr (ensures, ID_exists) || has_subexpr (ensures, ID_forall))
1546
1548
add_quantified_variable (ensures, function_symbol.mode );
1547
- common_replace (ensures);
1548
1549
1549
1550
// get all the relevant instructions related to history variables
1550
1551
auto assertion = code_assertt (ensures);
@@ -1567,8 +1568,8 @@ void code_contractst::add_contract_check(
1567
1568
for (auto &expr : requires_contract)
1568
1569
{
1569
1570
assume_function_pointer_obeys_contract (
1570
- to_function_pointer_obeys_contract_expr (expr),
1571
- common_replace ,
1571
+ to_function_pointer_obeys_contract_expr (
1572
+ to_lambda_expr (expr). application (instantiation_values)) ,
1572
1573
function_symbol.mode ,
1573
1574
check);
1574
1575
}
@@ -1586,9 +1587,9 @@ void code_contractst::add_contract_check(
1586
1587
for (auto &expr : ensures_contract)
1587
1588
{
1588
1589
assert_function_pointer_obeys_contract (
1589
- to_function_pointer_obeys_contract_expr (expr),
1590
+ to_function_pointer_obeys_contract_expr (
1591
+ to_lambda_expr (expr).application (instantiation_values)),
1590
1592
ID_postcondition,
1591
- common_replace,
1592
1593
function_symbol.mode ,
1593
1594
check);
1594
1595
}
0 commit comments