Skip to content

Commit 84ca5a0

Browse files
committed
conditional assigns clauses
1 parent fd26bcc commit 84ca5a0

File tree

2 files changed

+74
-31
lines changed

2 files changed

+74
-31
lines changed

regression/cprover/contracts/check_assigns6.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
check_assigns6.c
33

44
^EXIT=10$

src/cprover/instrument_contracts.cpp

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static bool is_symbol_member(const exprt &expr)
4444
static exprt
4545
make_assigns_assertion(const exprt::operandst &assigns, const exprt &lhs)
4646
{
47-
// trivial?
47+
// trivial match?
4848
if(is_symbol_member(lhs))
4949
{
5050
for(auto &a : assigns)
@@ -56,11 +56,28 @@ make_assigns_assertion(const exprt::operandst &assigns, const exprt &lhs)
5656

5757
for(auto &a : assigns)
5858
{
59-
auto a_address = make_address(a);
60-
auto lhs_address = make_address(lhs);
61-
lhs_address =
62-
typecast_exprt::conditional_cast(lhs_address, a_address.type());
63-
disjuncts.push_back(equal_exprt(a_address, lhs_address));
59+
if(a.id() == ID_conditional_target_group)
60+
{
61+
auto &condition = to_binary_expr(a).op0();
62+
auto &targets = to_multi_ary_expr(to_binary_expr(a).op1());
63+
for(auto &target : targets.operands())
64+
{
65+
auto target_address = make_address(target);
66+
auto lhs_address = make_address(lhs);
67+
lhs_address =
68+
typecast_exprt::conditional_cast(lhs_address, target_address.type());
69+
disjuncts.push_back(
70+
and_exprt(condition, equal_exprt(target_address, lhs_address)));
71+
}
72+
}
73+
else
74+
{
75+
auto target_address = make_address(a);
76+
auto lhs_address = make_address(lhs);
77+
lhs_address =
78+
typecast_exprt::conditional_cast(lhs_address, target_address.type());
79+
disjuncts.push_back(equal_exprt(target_address, lhs_address));
80+
}
6481
}
6582

6683
return disjunction(disjuncts);
@@ -288,6 +305,9 @@ void replace_function_calls_by_contracts(
288305
replace_symbol.insert(
289306
symbol_exprt("__CPROVER_return_value", call_lhs.type()), call_lhs);
290307

308+
goto_programt dest;
309+
310+
// assert the preconditions
291311
for(auto &precondition : contract.requires())
292312
{
293313
auto location = it->source_location();
@@ -298,32 +318,57 @@ void replace_function_calls_by_contracts(
298318
auto replaced_precondition = precondition;
299319
replace_symbol(replaced_precondition);
300320

301-
auto assertion_instruction =
302-
goto_programt::make_assertion(replaced_precondition, location);
303-
304-
body.insert_before_swap(it, assertion_instruction);
321+
dest.add(
322+
goto_programt::make_assertion(replaced_precondition, location));
305323
}
306324

307-
// advance the iterator
308-
it = std::next(it, contract.requires().size());
309-
310325
// havoc the 'assigned' variables
311-
for(auto &lhs : contract.assigns())
326+
for(auto &assigns_clause : contract.assigns())
312327
{
313328
auto location = it->source_location();
314329

315-
auto rhs = side_effect_expr_nondett(lhs.type(), location);
316-
auto replaced_lhs = lhs;
317-
replace_symbol(replaced_lhs);
330+
if(assigns_clause.id() == ID_conditional_target_group)
331+
{
332+
const auto &condition = to_binary_expr(assigns_clause).op0();
333+
auto replaced_condition = condition;
334+
replace_symbol(replaced_condition);
318335

319-
auto assignment_instruction =
320-
goto_programt::make_assignment(replaced_lhs, rhs, location);
336+
const auto &targets =
337+
to_multi_ary_expr(to_binary_expr(assigns_clause).op1())
338+
.operands();
321339

322-
body.insert_before_swap(it, assignment_instruction);
323-
}
340+
for(auto &target : targets)
341+
{
342+
auto rhs = side_effect_expr_nondett(target.type(), location);
324343

325-
// advance the iterator
326-
it = std::next(it, contract.assigns().size());
344+
auto replaced_lhs = target;
345+
replace_symbol(replaced_lhs);
346+
347+
auto goto_instruction =
348+
dest.add(goto_programt::make_incomplete_goto(
349+
not_exprt(replaced_condition), location));
350+
351+
dest.add(
352+
goto_programt::make_assignment(replaced_lhs, rhs, location));
353+
354+
auto skip_instruction =
355+
dest.add(goto_programt::make_skip(location));
356+
357+
goto_instruction->complete_goto(skip_instruction);
358+
}
359+
}
360+
else
361+
{
362+
const auto &lhs = assigns_clause;
363+
auto rhs = side_effect_expr_nondett(lhs.type(), location);
364+
365+
auto replaced_lhs = lhs;
366+
replace_symbol(replaced_lhs);
367+
368+
dest.add(
369+
goto_programt::make_assignment(replaced_lhs, rhs, location));
370+
}
371+
}
327372

328373
// assume the postconditions
329374
for(auto &postcondition : contract.ensures())
@@ -333,17 +378,15 @@ void replace_function_calls_by_contracts(
333378
auto replaced_postcondition = postcondition;
334379
replace_symbol(replaced_postcondition);
335380

336-
auto assumption_instruction =
337-
goto_programt::make_assumption(replaced_postcondition, location);
338-
339-
body.insert_before_swap(it, assumption_instruction);
381+
dest.add(
382+
goto_programt::make_assumption(replaced_postcondition, location));
340383
}
341384

342-
// advance the iterator
343-
it = std::next(it, contract.ensures().size());
344-
345385
// remove the function call
346386
it->turn_into_skip();
387+
388+
// insert after 'it' to preserve branches to the call
389+
body.destructive_insert(std::next(it), dest);
347390
}
348391
}
349392
}

0 commit comments

Comments
 (0)