Skip to content

Commit 9a0d532

Browse files
authored
Merge pull request #8299 from qinheping/issues/8298
[CONTRACTS] Refactor quantified symbol detection for loop contracts
2 parents c320360 + a7383d9 commit 9a0d532

File tree

4 files changed

+16
-44
lines changed

4 files changed

+16
-44
lines changed

regression/contracts-dfcc/quantifiers-loop-01/main.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
#include <assert.h>
2+
#include <stdbool.h>
23

34
#define N 16
45

56
void main()
67
{
78
int a[N];
89
a[10] = 0;
10+
bool flag = true;
911

1012
for(int i = 0; i < N; ++i)
1113
// clang-format off
1214
__CPROVER_assigns(i, __CPROVER_object_whole(a))
1315
__CPROVER_loop_invariant(
1416
(0 <= i) && (i <= N) &&
15-
__CPROVER_forall {
17+
flag == __CPROVER_forall {
1618
int k;
1719
// constant bounds for explicit unrolling with SAT backend
1820
(0 <= k && k <= N) ==> (

regression/contracts-dfcc/quantifiers-loop-01/test.desc

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
CORE dfcc-only
22
main.c
33
--dfcc main --apply-loop-contracts
4-
^\[main.loop_assigns.\d+\] line 10 Check assigns clause inclusion for loop .*: SUCCESS$
5-
^\[main.loop_invariant_base.\d+\] line 10 Check invariant before entry for loop .*: SUCCESS$
6-
^\[main.loop_invariant_step.\d+\] line 10 Check invariant after step for loop .*: SUCCESS$
7-
^\[main.loop_step_unwinding.\d+\] line 10 Check step was unwound for loop .*: SUCCESS$
4+
^\[main.loop_assigns.\d+\] line 12 Check assigns clause inclusion for loop .*: SUCCESS$
5+
^\[main.loop_invariant_base.\d+\] line 12 Check invariant before entry for loop .*: SUCCESS$
6+
^\[main.loop_invariant_step.\d+\] line 12 Check invariant after step for loop .*: SUCCESS$
7+
^\[main.loop_step_unwinding.\d+\] line 12 Check step was unwound for loop .*: SUCCESS$
88
^\[main.assigns.\d+\] line .* Check that i is assignable: SUCCESS$
99
^\[main.assigns.\d+\] line .* Check that a\[(\(signed (long (long )?)?int\))?i\] is assignable: SUCCESS$
1010
^\[main\.assertion\.\d+\] line .* assertion a\[10\] == 1: SUCCESS$

regression/contracts/quantifiers-loop-01/main.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
#include <assert.h>
2+
#include <stdbool.h>
23

34
#define N 16
45

56
void main()
67
{
78
int a[N];
89
a[10] = 0;
10+
bool flag = true;
911

1012
for(int i = 0; i < N; ++i)
1113
// clang-format off
1214
__CPROVER_assigns(i, __CPROVER_object_whole(a))
1315
__CPROVER_loop_invariant(
1416
(0 <= i) && (i <= N) &&
15-
__CPROVER_forall {
17+
flag == __CPROVER_forall {
1618
int k;
1719
// constant bounds for explicit unrolling with SAT backend
1820
(0 <= k && k <= N) ==> (

src/goto-instrument/contracts/utils.cpp

+6-38
Original file line numberDiff line numberDiff line change
@@ -369,46 +369,13 @@ void add_quantified_variable(
369369
exprt &expression,
370370
const irep_idt &mode)
371371
{
372-
if(expression.id() == ID_not || expression.id() == ID_typecast)
373-
{
374-
// For unary connectives, recursively check for
375-
// nested quantified formulae in the term
376-
auto &unary_expression = to_unary_expr(expression);
377-
add_quantified_variable(symbol_table, unary_expression.op(), mode);
378-
}
379-
if(expression.id() == ID_notequal || expression.id() == ID_implies)
380-
{
381-
// For binary connectives, recursively check for
382-
// nested quantified formulae in the left and right terms
383-
auto &binary_expression = to_binary_expr(expression);
384-
add_quantified_variable(symbol_table, binary_expression.lhs(), mode);
385-
add_quantified_variable(symbol_table, binary_expression.rhs(), mode);
386-
}
387-
if(expression.id() == ID_if)
388-
{
389-
// For ternary connectives, recursively check for
390-
// nested quantified formulae in all three terms
391-
auto &if_expression = to_if_expr(expression);
392-
add_quantified_variable(symbol_table, if_expression.cond(), mode);
393-
add_quantified_variable(symbol_table, if_expression.true_case(), mode);
394-
add_quantified_variable(symbol_table, if_expression.false_case(), mode);
395-
}
396-
if(expression.id() == ID_and || expression.id() == ID_or)
397-
{
398-
// For multi-ary connectives, recursively check for
399-
// nested quantified formulae in all terms
400-
auto &multi_ary_expression = to_multi_ary_expr(expression);
401-
for(auto &operand : multi_ary_expression.operands())
402-
{
403-
add_quantified_variable(symbol_table, operand, mode);
404-
}
405-
}
406-
else if(expression.id() == ID_exists || expression.id() == ID_forall)
407-
{
372+
auto visitor = [&symbol_table, &mode](exprt &expr) {
373+
if(expr.id() != ID_exists && expr.id() != ID_forall)
374+
return;
408375
// When a quantifier expression is found, create a fresh symbol for each
409376
// quantified variable and rewrite the expression to use those fresh
410377
// symbols.
411-
auto &quantifier_expression = to_quantifier_expr(expression);
378+
auto &quantifier_expression = to_quantifier_expr(expr);
412379
std::vector<symbol_exprt> fresh_variables;
413380
fresh_variables.reserve(quantifier_expression.variables().size());
414381
for(const auto &quantified_variable : quantifier_expression.variables())
@@ -435,7 +402,8 @@ void add_quantified_variable(
435402
// replace previous variables and body
436403
quantifier_expression.variables() = fresh_variables;
437404
quantifier_expression.where() = std::move(where);
438-
}
405+
};
406+
expression.visit_pre(visitor);
439407
}
440408

441409
static void replace_history_parameter_rec(

0 commit comments

Comments
 (0)