@@ -203,19 +203,31 @@ exprt struct_encodingt::encode(exprt expr) const
203
203
while (!work_queue.empty ())
204
204
{
205
205
exprt ¤t = *work_queue.front ();
206
- work_queue.pop ();
207
206
// Note that "with" expressions are handled before type encoding in order to
208
207
// facilitate checking that they are applied to structs rather than arrays.
209
208
if (const auto with_expr = expr_try_dynamic_cast<with_exprt>(current))
210
209
if (can_cast_type<struct_tag_typet>(current.type ()))
211
210
current = ::encode (*with_expr, ns);
212
211
current.type () = encode (current.type ());
212
+ optionalt<exprt> update;
213
213
if (const auto struct_expr = expr_try_dynamic_cast<struct_exprt>(current))
214
- current = ::encode (*struct_expr);
214
+ update = ::encode (*struct_expr);
215
215
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);
217
217
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 ();
219
231
for (auto &operand : current.operands ())
220
232
work_queue.push (&operand);
221
233
}
0 commit comments