@@ -344,6 +344,30 @@ void value_sett::get_value_set(
344344 get_value_set_rec (tmp, dest, " " , tmp.type (), ns);
345345}
346346
347+ // / Check if 'suffix' starts with 'field'.
348+ // / Suffix is delimited by periods and '[]' (array access) tokens, so we're
349+ // / looking for ".field($|[]|.)"
350+ static bool suffix_starts_with_field (
351+ const std::string &suffix, const std::string &field)
352+ {
353+ return
354+ !suffix.empty () &&
355+ suffix[0 ] == ' .' &&
356+ suffix.compare (1 , field.length (), field) == 0 &&
357+ (suffix.length () == field.length () + 1 ||
358+ suffix[field.length () + 1 ] == ' .' ||
359+ suffix[field.length () + 1 ] == ' [' );
360+ }
361+
362+ static std::string strip_first_field_from_suffix (
363+ const std::string &suffix, const std::string &field)
364+ {
365+ INVARIANT (
366+ suffix_starts_with_field (suffix, field),
367+ " suffix should start with " + field);
368+ return suffix.substr (field.length () + 1 );
369+ }
370+
347371void value_sett::get_value_set_rec (
348372 const exprt &expr,
349373 object_mapt &dest,
@@ -711,72 +735,113 @@ void value_sett::get_value_set_rec(
711735 }
712736 else if (expr.id ()==ID_struct)
713737 {
738+ const auto &struct_components = to_struct_type (expr_type).components ();
739+ INVARIANT (
740+ struct_components.size () == expr.operands ().size (),
741+ " struct expression should have an operand per component" );
742+ auto component_iter = struct_components.begin ();
743+ bool found_component = false ;
744+
714745 // a struct constructor, which may contain addresses
746+
715747 forall_operands (it, expr)
716- get_value_set_rec (*it, dest, suffix, original_type, ns);
748+ {
749+ const std::string &component_name =
750+ id2string (component_iter->get_name ());
751+ if (suffix_starts_with_field (suffix, component_name))
752+ {
753+ std::string remaining_suffix =
754+ strip_first_field_from_suffix (suffix, component_name);
755+ get_value_set_rec (*it, dest, remaining_suffix, original_type, ns);
756+ found_component = true ;
757+ }
758+ ++component_iter;
759+ }
760+
761+ if (!found_component)
762+ {
763+ // Struct field doesn't appear as expected -- this has probably been
764+ // cast from an incompatible type. Conservatively assume all fields may
765+ // be of interest.
766+ forall_operands (it, expr)
767+ get_value_set_rec (*it, dest, suffix, original_type, ns);
768+ }
717769 }
718770 else if (expr.id ()==ID_with)
719771 {
720- assert (expr.operands ().size ()==3 );
721-
722- // this is the array/struct
723- object_mapt tmp_map0;
724- get_value_set_rec (expr.op0 (), tmp_map0, suffix, original_type, ns);
772+ const with_exprt &with_expr = to_with_expr (expr);
725773
726- // this is the update value -- note NO SUFFIX
727- object_mapt tmp_map2;
728- get_value_set_rec (expr.op2 (), tmp_map2, " " , original_type, ns);
729-
730- if (expr_type.id ()==ID_struct)
774+ // If the suffix is empty we're looking for the whole struct:
775+ // default to combining both options as below.
776+ if (expr_type.id () == ID_struct && !suffix.empty ())
731777 {
732- #if 0
733- const object_map_dt &object_map0=tmp_map0.read();
734- irep_idt component_name=expr.op1().get(ID_component_name);
735-
736- bool insert=true;
737-
738- for(object_map_dt::const_iterator
739- it=object_map0.begin();
740- it!=object_map0.end();
741- it++)
778+ irep_idt component_name = with_expr.where ().get (ID_component_name);
779+ if (suffix_starts_with_field (suffix, id2string (component_name)))
742780 {
743- const exprt &e=to_expr(it);
744-
745- if(e.id()==ID_member &&
746- e.get(ID_component_name)==component_name)
747- {
748- if(insert)
749- {
750- dest.write().insert(tmp_map2.read().begin(), tmp_map2.read().end());
751- insert=false;
752- }
753- }
754- else
755- dest.write().insert(*it);
781+ // Looking for the member overwritten by this WITH expression
782+ std::string remaining_suffix =
783+ strip_first_field_from_suffix (suffix, id2string (component_name));
784+ get_value_set_rec (
785+ with_expr.new_value (), dest, remaining_suffix, original_type, ns);
786+ }
787+ else if (to_struct_type (expr_type).has_component (component_name))
788+ {
789+ // Looking for a non-overwritten member, look through this expression
790+ get_value_set_rec (with_expr.old (), dest, suffix, original_type, ns);
791+ }
792+ else
793+ {
794+ // Member we're looking for is not defined in this struct -- this
795+ // must be a reinterpret cast of some sort. Default to conservatively
796+ // assuming either operand might be involved.
797+ get_value_set_rec (expr.op0 (), dest, suffix, original_type, ns);
798+ get_value_set_rec (expr.op2 (), dest, " " , original_type, ns);
756799 }
757- #else
758- // Should be more precise! We only want "suffix"
759- make_union (dest, tmp_map0);
760- make_union (dest, tmp_map2);
761- #endif
800+ }
801+ else if (expr_type.id () == ID_array && !suffix.empty ())
802+ {
803+ std::string new_value_suffix;
804+ if (has_prefix (suffix, " []" ))
805+ new_value_suffix = suffix.substr (2 );
806+
807+ // Otherwise use a blank suffix on the assumption anything involved with
808+ // the new value might be interesting.
809+
810+ get_value_set_rec (with_expr.old (), dest, suffix, original_type, ns);
811+ get_value_set_rec (
812+ with_expr.new_value (), dest, new_value_suffix, original_type, ns);
762813 }
763814 else
764815 {
765- make_union (dest, tmp_map0);
766- make_union (dest, tmp_map2);
816+ // Something else-- the suffixes used here are a rough guess at best,
817+ // so this is imprecise.
818+ get_value_set_rec (expr.op0 (), dest, suffix, original_type, ns);
819+ get_value_set_rec (expr.op2 (), dest, " " , original_type, ns);
767820 }
768821 }
769822 else if (expr.id ()==ID_array)
770823 {
771824 // an array constructor, possibly containing addresses
825+ std::string new_suffix = suffix;
826+ if (has_prefix (suffix, " []" ))
827+ new_suffix = suffix.substr (2 );
828+ // Otherwise we're probably reinterpreting some other type -- try persisting
829+ // with the current suffix for want of a better idea.
830+
772831 forall_operands (it, expr)
773- get_value_set_rec (*it, dest, suffix , original_type, ns);
832+ get_value_set_rec (*it, dest, new_suffix , original_type, ns);
774833 }
775834 else if (expr.id ()==ID_array_of)
776835 {
777836 // an array constructor, possibly containing an address
837+ std::string new_suffix = suffix;
838+ if (has_prefix (suffix, " []" ))
839+ new_suffix = suffix.substr (2 );
840+ // Otherwise we're probably reinterpreting some other type -- try persisting
841+ // with the current suffix for want of a better idea.
842+
778843 assert (expr.operands ().size ()==1 );
779- get_value_set_rec (expr.op0 (), dest, suffix , original_type, ns);
844+ get_value_set_rec (expr.op0 (), dest, new_suffix , original_type, ns);
780845 }
781846 else if (expr.id ()==ID_dynamic_object)
782847 {
0 commit comments