@@ -654,6 +654,39 @@ code_contractst::create_ensures_instruction(
654654 return std::make_pair (std::move (ensures_program), std::move (history));
655655}
656656
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+
657690static const code_with_contract_typet &
658691get_contract (const irep_idt &function, const namespacet &ns)
659692{
@@ -768,36 +801,27 @@ void code_contractst::apply_function_contract(
768801 is_fresh.create_declarations ();
769802 is_fresh.add_memory_map_decl (new_program);
770803
771- // Insert assertion of the precondition immediately before the call site.
804+ // Generate: assert(requires)
772805 for (const auto &clause : type.requires ())
773806 {
774807 auto instantiated_clause =
775808 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);
801825 }
802826
803827 // Translate requires_contract(ptr, contract) clauses to assertions
@@ -812,26 +836,25 @@ void code_contractst::apply_function_contract(
812836 }
813837
814838 // 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 ())
818841 {
819842 auto instantiated_clause =
820843 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);
835858 }
836859
837860 // ASSIGNS clause should not refer to any quantified variables,
@@ -877,12 +900,26 @@ void code_contractst::apply_function_contract(
877900 // Insert havoc instructions immediately before the call site.
878901 new_program.destructive_append (havoc_instructions);
879902
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)
883905 {
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);
886923 }
887924
888925 // Translate ensures_contract(ptr, contract) clauses to assumptions
@@ -1446,57 +1483,47 @@ void code_contractst::add_contract_check(
14461483 {
14471484 auto instantiated_clause =
14481485 to_lambda_expr (clause).application (instantiation_values);
1449-
1450- if (!instantiated_clause.is_false ())
1486+ if (instantiated_clause.is_false ())
14511487 {
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." ));
14631492 }
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);
14641505 }
14651506
14661507 // 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 ())
14701510 {
1471- // Generate: copies for history variables
14721511 auto instantiated_clause =
14731512 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);
15001527 }
15011528
15021529 // Translate requires_contract(ptr, contract) clauses to assumptions
@@ -1513,9 +1540,18 @@ void code_contractst::add_contract_check(
15131540 check.add (goto_programt::make_function_call (call, source_location));
15141541
15151542 // Generate: assert(ensures)
1516- for (auto &pair : ensures_clauses )
1543+ for (auto &clause : instantiated_ensures_clauses )
15171544 {
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);
15191555 }
15201556
15211557 // Translate ensures_contract(ptr, contract) clauses to assertions
0 commit comments