Skip to content

Commit bafaddc

Browse files
committed
Fix encoding of structs which contain a single struct field
In the case where a struct contains a single struct typed field, then the construction of the outer class is encoded into the construction of the inner class which then itself needs to be encoded. Therefore the result of the encoding itself may need encoding. This general solution will also avoid further variations on the same issue such as constructing unions containing structs, or selecting struct fields from a union etc.
1 parent e798cbb commit bafaddc

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

src/solvers/smt2_incremental/encoding/struct_encoding.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,19 +203,31 @@ exprt struct_encodingt::encode(exprt expr) const
203203
while(!work_queue.empty())
204204
{
205205
exprt &current = *work_queue.front();
206-
work_queue.pop();
207206
// Note that "with" expressions are handled before type encoding in order to
208207
// facilitate checking that they are applied to structs rather than arrays.
209208
if(const auto with_expr = expr_try_dynamic_cast<with_exprt>(current))
210209
if(can_cast_type<struct_tag_typet>(current.type()))
211210
current = ::encode(*with_expr, ns);
212211
current.type() = encode(current.type());
212+
optionalt<exprt> update;
213213
if(const auto struct_expr = expr_try_dynamic_cast<struct_exprt>(current))
214-
current = ::encode(*struct_expr);
214+
update = ::encode(*struct_expr);
215215
if(const auto union_expr = expr_try_dynamic_cast<union_exprt>(current))
216-
current = ::encode(*union_expr, *boolbv_width);
216+
update = ::encode(*union_expr, *boolbv_width);
217217
if(const auto member_expr = expr_try_dynamic_cast<member_exprt>(current))
218-
current = encode_member(*member_expr);
218+
update = encode_member(*member_expr);
219+
if(update)
220+
{
221+
INVARIANT(
222+
current != *update,
223+
"Updates in struct encoding are expected to be a change of state.");
224+
current = std::move(*update);
225+
// Repeat on the updated node until we reach a fixed point. This is needed
226+
// because the encoding of an outer struct/union may be initially
227+
// expressed in terms of an inner struct/union which it contains.
228+
continue;
229+
}
230+
work_queue.pop();
219231
for(auto &operand : current.operands())
220232
work_queue.push(&operand);
221233
}

unit/solvers/smt2_incremental/encoding/struct_encoding.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,18 @@ TEST_CASE("struct encoding of expressions", "[core][smt2_incremental]")
169169
const concatenation_exprt expected_result{
170170
{green_ham.symbol_expr(), forty_two, minus_one}, bv_typet{72}};
171171
REQUIRE(test.struct_encoding.encode(struct_expr) == expected_result);
172+
SECTION("struct containing a single struct")
173+
{
174+
const struct_typet struct_struct_type{
175+
struct_union_typet::componentst{{"inner", struct_tag}}};
176+
const type_symbolt struct_struct_type_symbol{
177+
"struct_structt", struct_type, ID_C};
178+
test.symbol_table.insert(type_symbol);
179+
const struct_tag_typet struct_struct_tag{type_symbol.name};
180+
const struct_exprt struct_struct{
181+
exprt::operandst{struct_expr}, struct_struct_tag};
182+
REQUIRE(test.struct_encoding.encode(struct_struct) == expected_result);
183+
}
172184
}
173185
SECTION("member expression selecting a data member of a struct")
174186
{

0 commit comments

Comments
 (0)