Push empty-type equality short-circuit into convert_expr_to_smt#9015
Draft
tautschnig wants to merge 3 commits into
Draft
Push empty-type equality short-circuit into convert_expr_to_smt#9015tautschnig wants to merge 3 commits into
tautschnig wants to merge 3 commits into
Conversation
is_zero_width(const typet &, const namespacet &) was a file-static
helper in src/solvers/smt2/smt2_conv.cpp. The predicate is generic
('does this type have effective width of zero bits?') and not
specific to the non-incremental SMT2 backend; the incremental SMT2
backend will need exactly the same predicate to detect empty-typed
expressions correctly without re-treading the same struct/union/
struct-tag/union-tag/array recursion. Move the function to
src/util/pointer_offset_size.{h,cpp} alongside its semantic
neighbours pointer_offset_size and pointer_offset_bits, drop the
'static' qualifier on the original definition, and remove the
duplicate body from smt2_conv.cpp.
No functional change. smt2_conv.cpp continues to call is_zero_width
through the shared header (which it already includes); other
back-ends and util-level call sites can now do the same.
Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Skip zero-width-typed leaves (typically void) in
gather_dependent_expressions so that we never attempt to call
convert_type_to_smt_sort on them, which would hit
UNIMPLEMENTED_FEATURE. Handle the only top-level consumer that
could legitimately involve such a leaf -- equality of two
zero-width-typed operands -- by short-circuiting set_to: for
value == true the equality is vacuously satisfied (no command
emitted); for value == false we send `(assert false)` directly.
This matches the end-to-end behaviour of the non-incremental SMT2
backend, which converts equal_exprt over a zero-width type to
true_exprt and then negates.
Both filter sites use the shared is_zero_width predicate (now
exposed via util/pointer_offset_size.h) rather than a narrow
ID_empty check, so they stay correct even if struct_encoding's
pre-pass ever stops normalising other zero-width forms.
The set_to short-circuit handles only the top-level equality.
Nested cases such as and_exprt{equal_exprt{x_void, y_void}, other}
would still reach convert_expr_to_smt and trip
UNIMPLEMENTED_FEATURE; CBMC's GOTO programs do not produce such
nested shapes today, but pushing the short-circuit into the
equal_exprt overload of convert_expr_to_smt (mirroring
smt2_conv.cpp's structure more closely) is left as a follow-up.
Add a focused unit test in
unit/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp
covering both set_to(equal_exprt{void_x, void_y}, true) (no extra
commands sent) and set_to(..., false) (a single `(assert false)`).
Remove the no-new-smt exclusion tag from havoc_slice_checks and
memset_null regression tests since they now pass with the
incremental SMT2 backend.
Fixes: diffblue#8077
Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Previously, equality of two zero-width-typed (typically void)
operands was handled at the top level of
smt2_incremental_decision_proceduret::set_to: the `equal_exprt`
was matched textually before lowering reached convert_expr_to_smt,
and a dedicated branch emitted either nothing (for value == true)
or `(assert false)` (for value == false). This worked for the
common case but failed for nested shapes such as
set_to(and_exprt{equal_exprt{x_void, y_void}, other}, true)
because the recursive visitor in convert_expr_to_smt would still
descend into the void operands of the inner equal_exprt and trip
UNIMPLEMENTED_FEATURE in convert_type_to_smt_sort(empty_typet).
Move the short-circuit one layer down, into convert_expr_to_smt:
- Add a `const namespacet &` parameter to the public
convert_expr_to_smt and propagate it to the dispatcher and to
the equal_exprt overload.
- In the entry-point's `filtered_visit_post` filter, return false
for an `equal_exprt` whose operands have zero-width type, so
that the visitor does not descend into the void operands and
does not attempt convert_type_to_smt_sort on them.
- In the equal_exprt overload of convert_expr_to_smt, return
`smt_bool_literal_termt{true}` directly when the operand type
is zero-width, mirroring smt2_conv.cpp:1604
(`convert_expr(true_exprt())`).
- Drop the now-redundant top-level short-circuit from set_to:
convert_expr_to_smt produces the boolean literal `true`, which
set_to asserts as-is for value == true and negates for
value == false. This means the SMT output for the trivial
top-level case becomes `(assert true)` / `(assert (not true))`
rather than nothing / `(assert false)`. Both are semantically
equivalent and match the end-to-end behaviour of the
non-incremental SMT2 backend.
The gather-side filter in gather_dependent_expressions is kept:
it is a separate walk that runs before the convert-side visitor
and still needs to skip zero-width-typed leaves to avoid sending
declare-fun for them (which would also call
convert_type_to_smt_sort on an empty type).
Update the unit test for `set_to over empty type` to reflect the
new SMT command sequence, and add a new unit test
`set_to over nested empty-type equality` that exercises the nested
shape (an `and_exprt` whose lhs is an empty-type `equal_exprt`).
The existing `getting value of empty struct` test, which uses
empty structs (lowered to bv_typet{8} via struct_encoding) rather
than true void, continues to pass unchanged.
Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds upon #8907.
Previously, equality of two zero-width-typed (typically void) operands was handled at the top level of smt2_incremental_decision_proceduret::set_to: the
equal_exprtwas matched textually before lowering reached convert_expr_to_smt, and a dedicated branch emitted either nothing (for value == true) or(assert false)(for value == false). This worked for the common case but failed for nested shapes such asbecause the recursive visitor in convert_expr_to_smt would still descend into the void operands of the inner equal_exprt and trip UNIMPLEMENTED_FEATURE in convert_type_to_smt_sort(empty_typet).
Move the short-circuit one layer down, into convert_expr_to_smt:
const namespacet ¶meter to the public convert_expr_to_smt and propagate it to the dispatcher and to the equal_exprt overload.filtered_visit_postfilter, return false for anequal_exprtwhose operands have zero-width type, so that the visitor does not descend into the void operands and does not attempt convert_type_to_smt_sort on them.smt_bool_literal_termt{true}directly when the operand type is zero-width, mirroring smt2_conv.cpp:1604 (convert_expr(true_exprt())).true, which set_to asserts as-is for value == true and negates for value == false. This means the SMT output for the trivial top-level case becomes(assert true)/(assert (not true))rather than nothing /(assert false). Both are semantically equivalent and match the end-to-end behaviour of the non-incremental SMT2 backend.The gather-side filter in gather_dependent_expressions is kept: it is a separate walk that runs before the convert-side visitor and still needs to skip zero-width-typed leaves to avoid sending declare-fun for them (which would also call convert_type_to_smt_sort on an empty type).
Update the unit test for
set_to over empty typeto reflect the new SMT command sequence, and add a new unit testset_to over nested empty-type equalitythat exercises the nested shape (anand_exprtwhose lhs is an empty-typeequal_exprt). The existinggetting value of empty structtest, which uses empty structs (lowered to bv_typet{8} via struct_encoding) rather than true void, continues to pass unchanged.Co-authored-by: Kiro kiro-agent@users.noreply.github.com