Skip to content

Commit b35228a

Browse files
authored
Merge pull request #6214 from diffblue/multiple_invariants
Allow multiple loop invariants
2 parents e1365a6 + b06b263 commit b35228a

File tree

4 files changed

+36
-17
lines changed

4 files changed

+36
-17
lines changed

regression/contracts/invar_check_multiple_loops/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ int main()
77

88
for(r = 0; r < n; ++r)
99
// clang-format off
10-
__CPROVER_loop_invariant(0 <= r && r <= n && x == y + r)
10+
__CPROVER_loop_invariant(0 <= r && r <= n)
11+
__CPROVER_loop_invariant(x == y + r)
1112
__CPROVER_decreases(n - r)
1213
// clang-format on
1314
{

src/ansi-c/c_typecheck_code.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -815,10 +815,12 @@ void c_typecheck_baset::typecheck_spec_loop_invariant(codet &code)
815815
{
816816
if(code.find(ID_C_spec_loop_invariant).is_not_nil())
817817
{
818-
exprt &invariant = static_cast<exprt &>(code.add(ID_C_spec_loop_invariant));
819-
820-
typecheck_expr(invariant);
821-
implicit_typecast_bool(invariant);
818+
for(auto &invariant :
819+
(static_cast<exprt &>(code.add(ID_C_spec_loop_invariant)).operands()))
820+
{
821+
typecheck_expr(invariant);
822+
implicit_typecast_bool(invariant);
823+
}
822824
}
823825
}
824826

src/ansi-c/parser.y

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -491,11 +491,22 @@ quantifier_expression:
491491
}
492492
;
493493

494-
loop_invariant_opt:
494+
loop_invariant:
495+
TOK_CPROVER_LOOP_INVARIANT '(' ACSL_binding_expression ')'
496+
{ $$=$3; }
497+
;
498+
499+
loop_invariant_list:
500+
loop_invariant
501+
{ init($$); mto($$, $1); }
502+
| loop_invariant_list loop_invariant
503+
{ $$=$1; mto($$, $2); }
504+
;
505+
506+
loop_invariant_list_opt:
495507
/* nothing */
496508
{ init($$); parser_stack($$).make_nil(); }
497-
| TOK_CPROVER_LOOP_INVARIANT '(' ACSL_binding_expression ')'
498-
{ $$=$3; }
509+
| loop_invariant_list
499510
;
500511

501512
cprover_decreases_opt:
@@ -2426,28 +2437,28 @@ declaration_or_expression_statement:
24262437

24272438
iteration_statement:
24282439
TOK_WHILE '(' comma_expression_opt ')'
2429-
loop_invariant_opt cprover_decreases_opt
2440+
loop_invariant_list_opt cprover_decreases_opt
24302441
statement
24312442
{
24322443
$$=$1;
24332444
statement($$, ID_while);
24342445
parser_stack($$).add_to_operands(std::move(parser_stack($3)), std::move(parser_stack($7)));
24352446

2436-
if(parser_stack($5).is_not_nil())
2437-
parser_stack($$).add(ID_C_spec_loop_invariant).swap(parser_stack($5));
2447+
if(!parser_stack($5).operands().empty())
2448+
static_cast<exprt &>(parser_stack($$).add(ID_C_spec_loop_invariant)).operands().swap(parser_stack($5).operands());
24382449

24392450
if(parser_stack($6).is_not_nil())
24402451
parser_stack($$).add(ID_C_spec_decreases).swap(parser_stack($6));
24412452
}
24422453
| TOK_DO statement TOK_WHILE '(' comma_expression ')'
2443-
loop_invariant_opt cprover_decreases_opt ';'
2454+
loop_invariant_list_opt cprover_decreases_opt ';'
24442455
{
24452456
$$=$1;
24462457
statement($$, ID_dowhile);
24472458
parser_stack($$).add_to_operands(std::move(parser_stack($5)), std::move(parser_stack($2)));
24482459

2449-
if(parser_stack($7).is_not_nil())
2450-
parser_stack($$).add(ID_C_spec_loop_invariant).swap(parser_stack($7));
2460+
if(!parser_stack($7).operands().empty())
2461+
static_cast<exprt &>(parser_stack($$).add(ID_C_spec_loop_invariant)).operands().swap(parser_stack($7).operands());
24512462

24522463
if(parser_stack($8).is_not_nil())
24532464
parser_stack($$).add(ID_C_spec_decreases).swap(parser_stack($8));
@@ -2464,7 +2475,7 @@ iteration_statement:
24642475
'(' declaration_or_expression_statement
24652476
comma_expression_opt ';'
24662477
comma_expression_opt ')'
2467-
loop_invariant_opt cprover_decreases_opt
2478+
loop_invariant_list_opt cprover_decreases_opt
24682479
statement
24692480
{
24702481
$$=$1;
@@ -2475,8 +2486,8 @@ iteration_statement:
24752486
mto($$, $7);
24762487
mto($$, $11);
24772488

2478-
if(parser_stack($9).is_not_nil())
2479-
parser_stack($$).add(ID_C_spec_loop_invariant).swap(parser_stack($9));
2489+
if(!parser_stack($9).operands().empty())
2490+
static_cast<exprt &>(parser_stack($$).add(ID_C_spec_loop_invariant)).operands().swap(parser_stack($9).operands());
24802491

24812492
if(parser_stack($10).is_not_nil())
24822493
parser_stack($$).add(ID_C_spec_decreases).swap(parser_stack($10));

src/goto-instrument/code_contracts.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ void code_contractst::check_apply_loop_contracts(
149149
<< messaget::eom;
150150
}
151151
}
152+
else
153+
{
154+
// form the conjunction
155+
invariant = conjunction(invariant.operands());
156+
}
152157

153158
// change
154159
// H: loop;

0 commit comments

Comments
 (0)