Skip to content

Commit 322d054

Browse files
committed
Extend support for binding expressions beyond quantifiers
Symex special-cased some code for quantifiers when really all binding expressions have to be treated that way. To support this, add can_cast_expr<binding_exprt>, and make sure all subclasses of binding_exprt are covered by this cast.
1 parent 0c58a89 commit 322d054

File tree

3 files changed

+24
-13
lines changed

3 files changed

+24
-13
lines changed

src/goto-symex/symex_clean_expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ void goto_symext::lift_lets(statet &state, exprt &rhs)
212212

213213
it.next_sibling_or_parent();
214214
}
215-
else if(it->id() == ID_exists || it->id() == ID_forall)
215+
else if(can_cast_expr<binding_exprt>(*it))
216216
{
217217
// expressions within exists/forall may depend on bound variables, we
218218
// cannot safely lift let expressions out of those, just skip

src/goto-symex/symex_dereference.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -249,16 +249,16 @@ goto_symext::cache_dereference(exprt &dereference_result, statet &state)
249249
/// goto_symext::address_arithmetic) and certain common expression patterns
250250
/// such as `&struct.flexible_array[0]` (see inline comments in code).
251251
/// Note that \p write is used to alter behaviour when this function is
252-
/// operating on the LHS of an assignment. Similarly \p is_in_quantifier
253-
/// indicates when the dereference is inside a quantifier (related to scoping
254-
/// when dereference caching is enabled).
252+
/// operating on the LHS of an assignment. Similarly \p is_in_binding_expression
253+
/// indicates when the dereference is inside a binding expression (related to
254+
/// scoping when dereference caching is enabled).
255255
/// For full details of this method's pointer replacement and potential side-
256256
/// effects see \ref goto_symext::dereference
257257
void goto_symext::dereference_rec(
258258
exprt &expr,
259259
statet &state,
260260
bool write,
261-
bool is_in_quantifier)
261+
bool is_in_binding_expression)
262262
{
263263
if(expr.id()==ID_dereference)
264264
{
@@ -281,7 +281,7 @@ void goto_symext::dereference_rec(
281281
tmp1.swap(to_dereference_expr(expr).pointer());
282282

283283
// first make sure there are no dereferences in there
284-
dereference_rec(tmp1, state, false, is_in_quantifier);
284+
dereference_rec(tmp1, state, false, is_in_binding_expression);
285285

286286
// Depending on the nature of the pointer expression, the recursive deref
287287
// operation might have introduced a construct such as
@@ -345,7 +345,7 @@ void goto_symext::dereference_rec(
345345
// (p == &something ? something : ...))
346346
// Otherwise we should just return it unchanged.
347347
if(
348-
symex_config.cache_dereferences && !write && !is_in_quantifier &&
348+
symex_config.cache_dereferences && !write && !is_in_binding_expression &&
349349
(tmp2.id() == ID_if || tmp2.id() == ID_let))
350350
{
351351
expr = cache_dereference(tmp2, state);
@@ -372,7 +372,7 @@ void goto_symext::dereference_rec(
372372
tmp.add_source_location()=expr.source_location();
373373

374374
// recursive call
375-
dereference_rec(tmp, state, write, is_in_quantifier);
375+
dereference_rec(tmp, state, write, is_in_binding_expression);
376376

377377
expr.swap(tmp);
378378
}
@@ -405,18 +405,21 @@ void goto_symext::dereference_rec(
405405
expr = address_of_exprt(index_exprt(
406406
to_address_of_expr(tc_op).object(), from_integer(0, c_index_type())));
407407

408-
dereference_rec(expr, state, write, is_in_quantifier);
408+
dereference_rec(expr, state, write, is_in_binding_expression);
409409
}
410410
else
411411
{
412-
dereference_rec(tc_op, state, write, is_in_quantifier);
412+
dereference_rec(tc_op, state, write, is_in_binding_expression);
413413
}
414414
}
415415
else
416416
{
417-
bool is_quantifier = expr.id() == ID_forall || expr.id() == ID_exists;
417+
bool is_binding_expression = can_cast_expr<binding_exprt>(expr);
418418
Forall_operands(it, expr)
419-
dereference_rec(*it, state, write, is_in_quantifier || is_quantifier);
419+
{
420+
dereference_rec(
421+
*it, state, write, is_in_binding_expression || is_binding_expression);
422+
}
420423
}
421424
}
422425

src/util/std_expr.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3075,6 +3075,13 @@ class binding_exprt : public binary_exprt
30753075
exprt instantiate(const variablest &) const;
30763076
};
30773077

3078+
template <>
3079+
inline bool can_cast_expr<binding_exprt>(const exprt &base)
3080+
{
3081+
return base.id() == ID_forall || base.id() == ID_exists ||
3082+
base.id() == ID_lambda || base.id() == ID_array_comprehension;
3083+
}
3084+
30783085
inline void validate_expr(const binding_exprt &binding_expr)
30793086
{
30803087
validate_operands(
@@ -3090,7 +3097,8 @@ inline void validate_expr(const binding_exprt &binding_expr)
30903097
inline const binding_exprt &to_binding_expr(const exprt &expr)
30913098
{
30923099
PRECONDITION(
3093-
expr.id() == ID_forall || expr.id() == ID_exists || expr.id() == ID_lambda);
3100+
expr.id() == ID_forall || expr.id() == ID_exists ||
3101+
expr.id() == ID_lambda || expr.id() == ID_array_comprehension);
30943102
const binding_exprt &ret = static_cast<const binding_exprt &>(expr);
30953103
validate_expr(ret);
30963104
return ret;

0 commit comments

Comments
 (0)