Skip to content

Commit 25e6c7b

Browse files
committed
Fix quantifiers with nested statement-expressions
- Added support for `ID_address_of` and 'ID_typecast` expressions to `find_base_symbol`. - Corrected the multi-path handling in `convert_statement_expression`---a path not reaching the terminal expression should be ignored.
1 parent fab6710 commit 25e6c7b

File tree

3 files changed

+40
-9
lines changed

3 files changed

+40
-9
lines changed

Diff for: regression/cbmc/Quantifiers-statement-expression/main.c

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ int main()
33
// clang-format off
44
// no side effects!
55
int j = 0;
6-
//assert(j++);
7-
//assert(({int i = 0; while(i <3) i++; i <3;}));
86
int a[5] = {0 , 0, 0, 0, 0};
97
assert(__CPROVER_forall { int i; ({ int j = i; i=i; if(i < 0 || i >4) i = 1; ( a[i] < 5); }) });
108
// clang-format on
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
int main()
2+
{
3+
// clang-format off
4+
// no side effects!
5+
int j;
6+
int a[5] = {0 , 0, 0, 0, 0};
7+
assert(__CPROVER_forall { int i; ({ ( 0 <= i && i < 4) ==> ({ int k = j; if(j < 0 || j > i) k = 1; ( a[k] == 0); }); }) });
8+
// clang-format on
9+
10+
return 0;
11+
}

Diff for: src/ansi-c/goto-conversion/goto_clean_expr.cpp

+29-7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ static symbol_exprt find_base_symbol(const exprt &expr)
4343
{
4444
return find_base_symbol(to_dereference_expr(expr).pointer());
4545
}
46+
else if(expr.id() == ID_typecast)
47+
{
48+
return find_base_symbol(to_typecast_expr(expr).op());
49+
}
50+
else if(expr.id() == ID_address_of)
51+
{
52+
return find_base_symbol(to_address_of_expr(expr).op());
53+
}
4654
else
4755
{
4856
throw "unsupported expression type for finding base symbol";
@@ -63,6 +71,10 @@ static exprt convert_statement_expression(
6371
INVARIANT(
6472
natural_loops.loop_map.size() == 0, "quantifier must not contain loops");
6573

74+
std::unordered_set<symbol_exprt, irep_hash> declared_symbols;
75+
// All bound variables are local.
76+
declared_symbols.insert(qex.variables().begin(), qex.variables().end());
77+
6678
// `last` is the instruction corresponding to the last expression in the
6779
// statement expression.
6880
goto_programt::const_targett last = where.instructions.end();
@@ -75,13 +87,24 @@ static exprt convert_statement_expression(
7587
{
7688
last = it;
7789
}
90+
91+
if(it->is_decl())
92+
{
93+
declared_symbols.insert(it->decl_symbol());
94+
}
7895
}
7996

8097
DATA_INVARIANT(
8198
last != where.instructions.end(),
8299
"expression statements must contain a terminator expression");
83100

84101
auto last_expr = to_code_expression(last->get_other()).expression();
102+
if(
103+
last_expr.id() == ID_typecast &&
104+
to_typecast_expr(last_expr).type().id() == ID_empty)
105+
{
106+
to_typecast_expr(last_expr).type() = bool_typet();
107+
}
85108

86109
struct pathst
87110
{
@@ -139,10 +162,6 @@ static exprt convert_statement_expression(
139162
{1, where.instructions.begin()},
140163
{1, std::make_pair(true_exprt(), replace_mapt())});
141164

142-
std::unordered_set<symbol_exprt, irep_hash> declared_symbols;
143-
// All bound variables are local.
144-
declared_symbols.insert(qex.variables().begin(), qex.variables().end());
145-
146165
exprt res = true_exprt();
147166

148167
// Visit the quantifier body along `paths`.
@@ -151,9 +170,12 @@ static exprt convert_statement_expression(
151170
auto &current_it = paths.back_it();
152171
auto &path_condition = paths.back_path_condition();
153172
auto &value_map = paths.back_value_map();
154-
INVARIANT(
155-
current_it != where.instructions.end(),
156-
"Quantifier body must have a unique end expression.");
173+
174+
if(current_it == where.instructions.end())
175+
{
176+
paths.pop_back();
177+
continue;
178+
}
157179

158180
switch(current_it->type())
159181
{

0 commit comments

Comments
 (0)