@@ -654,6 +654,39 @@ code_contractst::create_ensures_instruction(
654
654
return std::make_pair (std::move (ensures_program), std::move (history));
655
655
}
656
656
657
+ // / This function generates instructions for all contract constraint, i.e.,
658
+ // / assumptions and assertions based on requires and ensures clauses.
659
+ static void generate_contract_constraints (
660
+ code_contractst &contract,
661
+ exprt &instantiated_clause,
662
+ const irep_idt &mode,
663
+ const std::function<void (goto_programt &)> &is_fresh_update,
664
+ goto_programt &program,
665
+ const source_locationt &location)
666
+ {
667
+ if (
668
+ has_subexpr (instantiated_clause, ID_exists) ||
669
+ has_subexpr (instantiated_clause, ID_forall))
670
+ {
671
+ contract.add_quantified_variable (instantiated_clause, mode);
672
+ }
673
+
674
+ goto_programt constraint;
675
+ if (location.get_property_class () == ID_assume)
676
+ {
677
+ contract.get_converter ().goto_convert (
678
+ code_assumet (instantiated_clause), constraint, mode);
679
+ }
680
+ else
681
+ {
682
+ contract.get_converter ().goto_convert (
683
+ code_assertt (instantiated_clause), constraint, mode);
684
+ }
685
+ constraint.instructions .back ().source_location_nonconst () = location;
686
+ is_fresh_update (constraint);
687
+ program.destructive_append (constraint);
688
+ }
689
+
657
690
static const code_with_contract_typet &
658
691
get_contract (const irep_idt &function, const namespacet &ns)
659
692
{
@@ -768,36 +801,27 @@ void code_contractst::apply_function_contract(
768
801
is_fresh.create_declarations ();
769
802
is_fresh.add_memory_map_decl (new_program);
770
803
771
- // Insert assertion of the precondition immediately before the call site.
804
+ // Generate: assert(requires)
772
805
for (const auto &clause : type.requires ())
773
806
{
774
807
auto instantiated_clause =
775
808
to_lambda_expr (clause).application (instantiation_values);
776
- if (!instantiated_clause.is_true ())
777
- {
778
- if (
779
- has_subexpr (instantiated_clause, ID_exists) ||
780
- has_subexpr (instantiated_clause, ID_forall))
781
- add_quantified_variable (instantiated_clause, mode);
782
-
783
- goto_programt assertion;
784
- converter.goto_convert (
785
- code_assertt (instantiated_clause), assertion, mode);
786
- assertion.instructions .back ().source_location_nonconst () =
787
- clause.source_location ();
788
- assertion.instructions .back ().source_location_nonconst ().set_line (
789
- location.get_line ());
790
- assertion.instructions .back ().source_location_nonconst ().set_comment (
791
- std::string (" Check " )
792
- .append (target_function.c_str ())
793
- .append (" 's requires clause in " )
794
- .append (function.c_str ()));
795
- assertion.instructions .back ()
796
- .source_location_nonconst ()
797
- .set_property_class (ID_precondition);
798
- is_fresh.update_requires (assertion);
799
- new_program.destructive_append (assertion);
800
- }
809
+ source_locationt _location = clause.source_location ();
810
+ _location.set_line (location.get_line ());
811
+ _location.set_comment (std::string (" Check requires clause of " )
812
+ .append (target_function.c_str ())
813
+ .append (" in " )
814
+ .append (function.c_str ()));
815
+ _location.set_property_class (ID_precondition);
816
+ generate_contract_constraints (
817
+ *this ,
818
+ instantiated_clause,
819
+ mode,
820
+ [&is_fresh](goto_programt &requires ) {
821
+ is_fresh.update_requires (requires );
822
+ },
823
+ new_program,
824
+ _location);
801
825
}
802
826
803
827
// Translate requires_contract(ptr, contract) clauses to assertions
@@ -812,26 +836,25 @@ void code_contractst::apply_function_contract(
812
836
}
813
837
814
838
// Gather all the instructions required to handle history variables
815
- // as well as the ensures clause
816
- std::vector<std::pair<goto_programt, goto_programt>> ensures_clauses;
817
- for (const auto &clause : type.ensures ())
839
+ std::vector<exprt> instantiated_ensures_clauses;
840
+ for (auto clause : type.ensures ())
818
841
{
819
842
auto instantiated_clause =
820
843
to_lambda_expr (clause).application (instantiation_values);
821
- if (! instantiated_clause.is_false ())
822
- {
823
- if (
824
- has_subexpr (instantiated_clause, ID_exists) ||
825
- has_subexpr (instantiated_clause, ID_forall))
826
- add_quantified_variable ( instantiated_clause, mode);
827
-
828
- auto assumption = code_assumet (instantiated_clause);
829
- ensures_clauses. push_back (
830
- create_ensures_instruction (assumption, clause. source_location (), mode));
831
-
832
- // add all the history variable initialization instructions
833
- new_program. destructive_append (ensures_clauses. back (). second );
834
- }
844
+ instantiated_clause.add_source_location () = clause. source_location ();
845
+ std::map<exprt, exprt> parameter2history;
846
+ goto_programt history;
847
+ // Find and replace "old" expression in the "expression" variable
848
+ replace_history_parameter (
849
+ instantiated_clause,
850
+ parameter2history,
851
+ clause. source_location (),
852
+ mode,
853
+ history,
854
+ ID_old);
855
+ instantiated_ensures_clauses. push_back (instantiated_clause);
856
+ // Add all the history variable initialization instructions
857
+ new_program. destructive_append (history);
835
858
}
836
859
837
860
// ASSIGNS clause should not refer to any quantified variables,
@@ -877,12 +900,26 @@ void code_contractst::apply_function_contract(
877
900
// Insert havoc instructions immediately before the call site.
878
901
new_program.destructive_append (havoc_instructions);
879
902
880
- // To remove the function call, insert statements related to the assumption.
881
- // Then, replace the function call with a SKIP statement.
882
- for (auto &clause : ensures_clauses)
903
+ // Generate: assume(ensures)
904
+ for (auto &clause : instantiated_ensures_clauses)
883
905
{
884
- is_fresh.update_ensures (clause.first );
885
- new_program.destructive_append (clause.first );
906
+ if (clause.is_false ())
907
+ {
908
+ throw invalid_input_exceptiont (
909
+ std::string (" Attempt to assume false at " )
910
+ .append (clause.source_location ().as_string ())
911
+ .append (" .\n Please update ensures clause to avoid vacuity." ));
912
+ }
913
+ source_locationt _location = clause.source_location ();
914
+ _location.set_comment (" Assume ensures clause" );
915
+ _location.set_property_class (ID_assume);
916
+ generate_contract_constraints (
917
+ *this ,
918
+ clause,
919
+ mode,
920
+ [&is_fresh](goto_programt &ensures) { is_fresh.update_ensures (ensures); },
921
+ new_program,
922
+ _location);
886
923
}
887
924
888
925
// Translate ensures_contract(ptr, contract) clauses to assumptions
@@ -1446,57 +1483,47 @@ void code_contractst::add_contract_check(
1446
1483
{
1447
1484
auto instantiated_clause =
1448
1485
to_lambda_expr (clause).application (instantiation_values);
1449
-
1450
- if (!instantiated_clause.is_false ())
1486
+ if (instantiated_clause.is_false ())
1451
1487
{
1452
- if (
1453
- has_subexpr (instantiated_clause, ID_exists) ||
1454
- has_subexpr (instantiated_clause, ID_forall))
1455
- add_quantified_variable (instantiated_clause, function_symbol.mode );
1456
-
1457
- goto_programt assumption;
1458
- converter.goto_convert (
1459
- code_assumet (instantiated_clause), assumption, function_symbol.mode );
1460
-
1461
- visitor.update_requires (assumption);
1462
- check.destructive_append (assumption);
1488
+ throw invalid_input_exceptiont (
1489
+ std::string (" Attempt to assume false at " )
1490
+ .append (clause.source_location ().as_string ())
1491
+ .append (" .\n Please update requires clause to avoid vacuity." ));
1463
1492
}
1493
+ source_locationt _location = clause.source_location ();
1494
+ _location.set_comment (" Assume requires clause" );
1495
+ _location.set_property_class (ID_assume);
1496
+ generate_contract_constraints (
1497
+ *this ,
1498
+ instantiated_clause,
1499
+ function_symbol.mode ,
1500
+ [&visitor](goto_programt &requires ) {
1501
+ visitor.update_requires (requires );
1502
+ },
1503
+ check,
1504
+ _location);
1464
1505
}
1465
1506
1466
1507
// Gather all the instructions required to handle history variables
1467
- // as well as the ensures clause
1468
- std::vector<std::pair<goto_programt, goto_programt>> ensures_clauses;
1469
- for (const auto &clause : code_type.ensures ())
1508
+ std::vector<exprt> instantiated_ensures_clauses;
1509
+ for (auto clause : code_type.ensures ())
1470
1510
{
1471
- // Generate: copies for history variables
1472
1511
auto instantiated_clause =
1473
1512
to_lambda_expr (clause).application (instantiation_values);
1474
-
1475
- if (!instantiated_clause.is_true ())
1476
- {
1477
- if (
1478
- has_subexpr (instantiated_clause, ID_exists) ||
1479
- has_subexpr (instantiated_clause, ID_forall))
1480
- add_quantified_variable (instantiated_clause, function_symbol.mode );
1481
-
1482
- // get all the relevant instructions related to history variables
1483
- auto assertion = code_assertt (instantiated_clause);
1484
- assertion.add_source_location () = clause.source_location ();
1485
- ensures_clauses.push_back (create_ensures_instruction (
1486
- assertion, clause.source_location (), function_symbol.mode ));
1487
- ensures_clauses.back ()
1488
- .first .instructions .back ()
1489
- .source_location_nonconst ()
1490
- .set_comment (" Check ensures clause" );
1491
- ensures_clauses.back ()
1492
- .first .instructions .back ()
1493
- .source_location_nonconst ()
1494
- .set_property_class (ID_postcondition);
1495
-
1496
- // add all the history variable initializations
1497
- visitor.update_ensures (ensures_clauses.back ().first );
1498
- check.destructive_append (ensures_clauses.back ().second );
1499
- }
1513
+ instantiated_clause.add_source_location () = clause.source_location ();
1514
+ std::map<exprt, exprt> parameter2history;
1515
+ goto_programt history;
1516
+ // Find and replace "old" expression in the "expression" variable
1517
+ replace_history_parameter (
1518
+ instantiated_clause,
1519
+ parameter2history,
1520
+ clause.source_location (),
1521
+ function_symbol.mode ,
1522
+ history,
1523
+ ID_old);
1524
+ instantiated_ensures_clauses.push_back (instantiated_clause);
1525
+ // Add all the history variable initialization instructions
1526
+ check.destructive_append (history);
1500
1527
}
1501
1528
1502
1529
// Translate requires_contract(ptr, contract) clauses to assumptions
@@ -1513,9 +1540,18 @@ void code_contractst::add_contract_check(
1513
1540
check.add (goto_programt::make_function_call (call, source_location));
1514
1541
1515
1542
// Generate: assert(ensures)
1516
- for (auto &pair : ensures_clauses )
1543
+ for (auto &clause : instantiated_ensures_clauses )
1517
1544
{
1518
- check.destructive_append (pair.first );
1545
+ source_locationt _location = clause.source_location ();
1546
+ _location.set_comment (" Check ensures clause" );
1547
+ _location.set_property_class (ID_postcondition);
1548
+ generate_contract_constraints (
1549
+ *this ,
1550
+ clause,
1551
+ function_symbol.mode ,
1552
+ [&visitor](goto_programt &ensures) { visitor.update_ensures (ensures); },
1553
+ check,
1554
+ _location);
1519
1555
}
1520
1556
1521
1557
// Translate ensures_contract(ptr, contract) clauses to assertions
0 commit comments