CBMC
value_set_fi.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Value Set (Flow Insensitive, Sharing)
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "value_set_fi.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/byte_operators.h>
16 #include <util/c_types.h>
17 #include <util/expr_util.h>
18 #include <util/namespace.h>
19 #include <util/pointer_expr.h>
20 #include <util/simplify_expr.h>
21 #include <util/std_code.h>
22 #include <util/symbol.h>
23 
25 
26 #include <langapi/language_util.h>
27 
28 #include <ostream>
29 
31 
34 
35 static const char *alloc_adapter_prefix="alloc_adaptor::";
36 
38  const namespacet &ns,
39  std::ostream &out) const
40 {
41  for(valuest::const_iterator
42  v_it=values.begin();
43  v_it!=values.end();
44  v_it++)
45  {
46  irep_idt identifier, display_name;
47 
48  const entryt &e=v_it->second;
49 
50  if(e.identifier.starts_with("value_set::dynamic_object"))
51  {
52  display_name=id2string(e.identifier)+e.suffix;
53  identifier.clear();
54  }
55  else
56  {
57  #if 0
58  const symbolt &symbol=ns.lookup(id2string(e.identifier));
59  display_name=symbol.display_name()+e.suffix;
60  identifier=symbol.name;
61  #else
62  identifier=id2string(e.identifier);
63  display_name=id2string(identifier)+e.suffix;
64  #endif
65  }
66 
67  out << display_name;
68 
69  out << " = { ";
70 
71  object_mapt object_map;
72  flatten(e, object_map);
73 
74  std::size_t width=0;
75 
76  const auto &entries = object_map.read();
77  for(object_map_dt::const_iterator o_it = entries.begin();
78  o_it != entries.end();
79  ++o_it)
80  {
81  const exprt &o=object_numbering[o_it->first];
82 
83  std::string result;
84 
85  if(o.id()==ID_invalid || o.id()==ID_unknown)
86  {
87  result="<";
88  result+=from_expr(ns, identifier, o);
89  result+=", *, "; // offset unknown
90  if(o.type().id()==ID_unknown)
91  result+='*';
92  else
93  result+=from_type(ns, identifier, o.type());
94  result+='>';
95  }
96  else
97  {
98  result="<"+from_expr(ns, identifier, o)+", ";
99 
100  if(o_it->second)
101  result += integer2string(*o_it->second);
102  else
103  result+='*';
104 
105  result+=", ";
106 
107  if(o.type().id()==ID_unknown)
108  result+='*';
109  else
110  result+=from_type(ns, identifier, o.type());
111 
112  result+='>';
113  }
114 
115  out << result;
116 
117  width+=result.size();
118 
120  next++;
121 
122  if(next != entries.end())
123  {
124  out << ", ";
125  if(width>=40)
126  out << "\n ";
127  }
128  }
129 
130  out << " } \n";
131  }
132 }
133 
135  const entryt &e,
136  object_mapt &dest) const
137 {
138  #if 0
139  std::cout << "FLATTEN: " << e.identifier << e.suffix << '\n';
140  #endif
141 
142  flatten_seent seen;
143  flatten_rec(e, dest, seen);
144 
145  #if 0
146  std::cout << "FLATTEN: Done.\n";
147  #endif
148 }
149 
151  const entryt &e,
152  object_mapt &dest,
153  flatten_seent &seen) const
154 {
155  #if 0
156  std::cout << "FLATTEN_REC: " << e.identifier << e.suffix << '\n';
157  #endif
158 
159  std::string identifier = id2string(e.identifier);
160  CHECK_RETURN(seen.find(identifier + e.suffix) == seen.end());
161 
162  bool generalize_index = false;
163 
164  seen.insert(identifier + e.suffix);
165 
166  for(const auto &object_entry : e.object_map.read())
167  {
168  const exprt &o = object_numbering[object_entry.first];
169 
170  if(o.type().id()=="#REF#")
171  {
172  if(seen.find(o.get(ID_identifier))!=seen.end())
173  {
174  generalize_index = true;
175  continue;
176  }
177 
178  valuest::const_iterator fi = values.find(o.get(ID_identifier));
179  if(fi==values.end())
180  {
181  // this is some static object, keep it in.
182  const symbol_exprt se(
183  o.get(ID_identifier), to_type_with_subtype(o.type()).subtype());
184  insert(dest, se, mp_integer{0});
185  }
186  else
187  {
188  object_mapt temp;
189  flatten_rec(fi->second, temp, seen);
190 
191  for(object_map_dt::iterator t_it=temp.write().begin();
192  t_it!=temp.write().end();
193  t_it++)
194  {
195  if(t_it->second && object_entry.second)
196  {
197  *t_it->second += *object_entry.second;
198  }
199  else
200  t_it->second.reset();
201  }
202 
203  for(const auto &object_entry : temp.read())
204  insert(dest, object_entry);
205  }
206  }
207  else
208  insert(dest, object_entry);
209  }
210 
211  if(generalize_index) // this means we had recursive symbols in there
212  {
213  for(auto &object_entry : dest.write())
214  object_entry.second.reset();
215  }
216 
217  seen.erase(identifier + e.suffix);
218 }
219 
221 {
222  const exprt &object=object_numbering[it.first];
223 
224  if(object.id()==ID_invalid ||
225  object.id()==ID_unknown)
226  return object;
227 
229 
230  od.object()=object;
231 
232  if(it.second)
233  od.offset() = from_integer(*it.second, c_index_type());
234 
235  od.type()=od.object().type();
236 
237  return std::move(od);
238 }
239 
241 {
242  UNREACHABLE;
243  bool result=false;
244 
245  for(valuest::const_iterator
246  it=new_values.begin();
247  it!=new_values.end();
248  it++)
249  {
250  valuest::iterator it2=values.find(it->first);
251 
252  if(it2==values.end())
253  {
254  // we always track these
255  if(
256  it->second.identifier.starts_with("value_set::dynamic_object") ||
257  it->second.identifier.starts_with("value_set::return_value"))
258  {
259  values.insert(*it);
260  result=true;
261  }
262 
263  continue;
264  }
265 
266  entryt &e=it2->second;
267  const entryt &new_e=it->second;
268 
269  if(make_union(e.object_map, new_e.object_map))
270  result=true;
271  }
272 
273  changed = result;
274 
275  return result;
276 }
277 
278 bool value_set_fit::make_union(object_mapt &dest, const object_mapt &src) const
279 {
280  bool result=false;
281 
282  for(const auto &object_entry : src.read())
283  {
284  if(insert(dest, object_entry))
285  result=true;
286  }
287 
288  return result;
289 }
290 
291 std::vector<exprt>
292 value_set_fit::get_value_set(const exprt &expr, const namespacet &ns) const
293 {
294  object_mapt object_map;
295  get_value_set(expr, object_map, ns);
296 
297  object_mapt flat_map;
298 
299  for(const auto &object_entry : object_map.read())
300  {
301  const exprt &object = object_numbering[object_entry.first];
302  if(object.type().id()=="#REF#")
303  {
304  DATA_INVARIANT(object.id() == ID_symbol, "reference to symbol required");
305 
306  const irep_idt &ident = object.get(ID_identifier);
307  valuest::const_iterator v_it = values.find(ident);
308 
309  if(v_it!=values.end())
310  {
311  object_mapt temp;
312  flatten(v_it->second, temp);
313 
314  for(object_map_dt::iterator t_it=temp.write().begin();
315  t_it!=temp.write().end();
316  t_it++)
317  {
318  if(t_it->second && object_entry.second)
319  {
320  *t_it->second += *object_entry.second;
321  }
322  else
323  t_it->second.reset();
324 
325  flat_map.write()[t_it->first]=t_it->second;
326  }
327  }
328  }
329  else
330  flat_map.write()[object_entry.first] = object_entry.second;
331  }
332 
333  std::vector<exprt> result;
334  for(const auto &object_entry : flat_map.read())
335  result.push_back(to_expr(object_entry));
336 
337 #if 0
338  // Sanity check!
339  for(std::list<exprt>::const_iterator it=value_set.begin();
340  it!=value_set.end();
341  it++)
342  assert(it->type().id()!="#REF");
343 #endif
344 
345 #if 0
346  for(expr_sett::const_iterator it=value_set.begin(); it!=value_set.end(); it++)
347  std::cout << "GET_VALUE_SET: " << format(*it) << '\n';
348 #endif
349 
350  return result;
351 }
352 
354  const exprt &expr,
355  object_mapt &dest,
356  const namespacet &ns) const
357 {
358  exprt tmp(expr);
359  simplify(tmp, ns);
360 
361  gvs_recursion_sett recset;
362  bool includes_nondet_pointer = false;
364  tmp, dest, includes_nondet_pointer, "", tmp.type(), ns, recset);
365 }
366 
368  const exprt &expr,
369  object_mapt &dest,
370  bool &includes_nondet_pointer,
371  const std::string &suffix,
372  const typet &original_type,
373  const namespacet &ns,
374  gvs_recursion_sett &recursion_set) const
375 {
376  #if 0
377  std::cout << "GET_VALUE_SET_REC EXPR: " << format(expr)
378  << '\n';
379  std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << '\n';
380  std::cout << '\n';
381  #endif
382 
383  if(expr.type().id()=="#REF#")
384  {
385  valuest::const_iterator fi = values.find(expr.get(ID_identifier));
386 
387  if(fi!=values.end())
388  {
389  for(const auto &object_entry : fi->second.object_map.read())
390  {
392  object_numbering[object_entry.first],
393  dest,
394  includes_nondet_pointer,
395  suffix,
396  original_type,
397  ns,
398  recursion_set);
399  }
400  return;
401  }
402  else
403  {
404  insert(dest, exprt(ID_unknown, original_type));
405  return;
406  }
407  }
408  else if(expr.id()==ID_unknown || expr.id()==ID_invalid)
409  {
410  insert(dest, exprt(ID_unknown, original_type));
411  return;
412  }
413  else if(expr.id()==ID_index)
414  {
415  const typet &type = to_index_expr(expr).array().type();
416 
417  if(type.id() == ID_array)
418  {
420  to_index_expr(expr).array(),
421  dest,
422  includes_nondet_pointer,
423  "[]" + suffix,
424  original_type,
425  ns,
426  recursion_set);
427  }
428  else
429  insert(dest, exprt(ID_unknown, original_type));
430 
431  return;
432  }
433  else if(expr.id()==ID_member)
434  {
435  const auto &compound = to_member_expr(expr).compound();
436 
437  if(compound.is_not_nil())
438  {
439  const typet &type = ns.follow(compound.type());
440 
442  type.id() == ID_struct || type.id() == ID_union,
443  "operand 0 of member expression must be struct or union");
444 
445  const std::string &component_name =
446  id2string(to_member_expr(expr).get_component_name());
447 
449  compound,
450  dest,
451  includes_nondet_pointer,
452  "." + component_name + suffix,
453  original_type,
454  ns,
455  recursion_set);
456 
457  return;
458  }
459  }
460  else if(expr.id()==ID_symbol)
461  {
462  // just keep a reference to the ident in the set
463  // (if it exists)
464  irep_idt ident = id2string(to_symbol_expr(expr).get_identifier()) + suffix;
465  valuest::const_iterator v_it=values.find(ident);
466 
468  {
469  insert(dest, expr, mp_integer{0});
470  return;
471  }
472  else if(v_it!=values.end())
473  {
474  type_with_subtypet t("#REF#", expr.type());
475  symbol_exprt sym(ident, t);
476  insert(dest, sym, mp_integer{0});
477  return;
478  }
479  }
480  else if(expr.id()==ID_if)
481  {
483  to_if_expr(expr).true_case(),
484  dest,
485  includes_nondet_pointer,
486  suffix,
487  original_type,
488  ns,
489  recursion_set);
491  to_if_expr(expr).false_case(),
492  dest,
493  includes_nondet_pointer,
494  suffix,
495  original_type,
496  ns,
497  recursion_set);
498 
499  return;
500  }
501  else if(expr.id()==ID_address_of)
502  {
503  get_reference_set_sharing(to_address_of_expr(expr).object(), dest, ns);
504 
505  return;
506  }
507  else if(expr.id()==ID_dereference)
508  {
509  object_mapt reference_set;
510  get_reference_set_sharing(expr, reference_set, ns);
511  const object_map_dt &object_map=reference_set.read();
512 
513  if(object_map.begin()!=object_map.end())
514  {
515  for(const auto &object_entry : object_map)
516  {
517  const exprt &object = object_numbering[object_entry.first];
519  object,
520  dest,
521  includes_nondet_pointer,
522  suffix,
523  original_type,
524  ns,
525  recursion_set);
526  }
527 
528  return;
529  }
530  }
531  else if(expr.is_constant())
532  {
533  // check if NULL
535  {
536  insert(
537  dest,
538  exprt(ID_null_object, to_pointer_type(expr.type()).base_type()),
539  mp_integer{0});
540  return;
541  }
542  }
543  else if(expr.id()==ID_typecast)
544  {
546  to_typecast_expr(expr).op(),
547  dest,
548  includes_nondet_pointer,
549  suffix,
550  original_type,
551  ns,
552  recursion_set);
553 
554  return;
555  }
556  else if(expr.id()==ID_plus || expr.id()==ID_minus)
557  {
558  if(expr.operands().size()<2)
559  throw expr.id_string()+" expected to have at least two operands";
560 
561  if(expr.type().id()==ID_pointer)
562  {
563  // find the pointer operand
564  const exprt *ptr_operand=nullptr;
565 
566  for(const auto &op : expr.operands())
567  {
568  if(op.type().id() == ID_pointer)
569  {
570  if(ptr_operand==nullptr)
571  ptr_operand = &op;
572  else
573  throw "more than one pointer operand in pointer arithmetic";
574  }
575  }
576 
577  if(ptr_operand==nullptr)
578  throw "pointer type sum expected to have pointer operand";
579 
580  object_mapt pointer_expr_set;
582  *ptr_operand,
583  pointer_expr_set,
584  includes_nondet_pointer,
585  "",
586  ptr_operand->type(),
587  ns,
588  recursion_set);
589 
590  for(const auto &object_entry : pointer_expr_set.read())
591  {
592  offsett offset = object_entry.second;
593 
594  if(offset_is_zero(offset) && expr.operands().size() == 2)
595  {
596  if(to_binary_expr(expr).op0().type().id() != ID_pointer)
597  {
598  const auto i = numeric_cast<mp_integer>(to_binary_expr(expr).op0());
599  if(!i.has_value())
600  offset.reset();
601  else
602  *offset = (expr.id() == ID_plus) ? *i : -*i;
603  }
604  else
605  {
606  const auto i = numeric_cast<mp_integer>(to_binary_expr(expr).op1());
607  if(!i.has_value())
608  offset.reset();
609  else
610  *offset = (expr.id() == ID_plus) ? *i : -*i;
611  }
612  }
613  else
614  offset.reset();
615 
616  insert(dest, object_entry.first, offset);
617  }
618 
619  return;
620  }
621  }
622  else if(expr.id()==ID_side_effect)
623  {
624  const irep_idt &statement = to_side_effect_expr(expr).get_statement();
625 
626  if(statement==ID_function_call)
627  {
628  // these should be gone
629  throw "unexpected function_call sideeffect";
630  }
631  else if(statement==ID_allocate)
632  {
633  if(expr.type().id()!=ID_pointer)
634  throw "malloc expected to return pointer type";
635 
636  PRECONDITION(suffix.empty());
637 
638  const typet &dynamic_type=
639  static_cast<const typet &>(expr.find(ID_C_cxx_alloc_type));
640 
641  dynamic_object_exprt dynamic_object(dynamic_type);
642  // let's make up a `unique' number for this object...
643  dynamic_object.set_instance(
644  (from_function << 16) | from_target_index);
645  dynamic_object.valid()=true_exprt();
646 
647  insert(dest, dynamic_object, mp_integer{0});
648  return;
649  }
650  else if(statement==ID_cpp_new ||
651  statement==ID_cpp_new_array)
652  {
653  PRECONDITION(suffix.empty());
654  PRECONDITION(expr.type().id() == ID_pointer);
655 
656  dynamic_object_exprt dynamic_object(
657  to_pointer_type(expr.type()).base_type());
658  dynamic_object.set_instance(
659  (from_function << 16) | from_target_index);
660  dynamic_object.valid()=true_exprt();
661 
662  insert(dest, dynamic_object, mp_integer{0});
663  return;
664  }
665  }
666  else if(expr.id()==ID_struct)
667  {
668  // this is like a static struct object
669  insert(dest, address_of_exprt(expr), mp_integer{0});
670  return;
671  }
672  else if(expr.id()==ID_with)
673  {
674  // these are supposed to be done by assign()
675  throw "unexpected value in get_value_set: "+expr.id_string();
676  }
677  else if(expr.id()==ID_array_of ||
678  expr.id()==ID_array)
679  {
680  // an array constructor, possibly containing addresses
681  for(const auto &op : expr.operands())
682  {
684  op,
685  dest,
686  includes_nondet_pointer,
687  suffix,
688  original_type,
689  ns,
690  recursion_set);
691  }
692  }
693  else if(expr.id()==ID_dynamic_object)
694  {
695  const dynamic_object_exprt &dynamic_object=
697 
698  const std::string name=
699  "value_set::dynamic_object"+
700  std::to_string(dynamic_object.get_instance())+
701  suffix;
702 
703  // look it up
704  valuest::const_iterator v_it=values.find(name);
705 
706  if(v_it!=values.end())
707  {
708  make_union(dest, v_it->second.object_map);
709  return;
710  }
711  }
712 
713  insert(dest, exprt(ID_unknown, original_type));
714 }
715 
717  const exprt &src,
718  exprt &dest) const
719 {
720  // remove pointer typecasts
721  if(src.id()==ID_typecast)
722  {
723  PRECONDITION(src.type().id() == ID_pointer);
724 
725  dereference_rec(to_typecast_expr(src).op(), dest);
726  }
727  else
728  dest=src;
729 }
730 
732  const exprt &expr,
733  expr_sett &dest,
734  const namespacet &ns) const
735 {
736  object_mapt object_map;
737  get_reference_set_sharing(expr, object_map, ns);
738 
739  for(const auto &object_entry : object_map.read())
740  {
741  const exprt &object = object_numbering[object_entry.first];
742 
743  if(object.type().id() == "#REF#")
744  {
745  const irep_idt &ident = object.get(ID_identifier);
746  valuest::const_iterator vit = values.find(ident);
747  if(vit==values.end())
748  {
749  // Assume the variable never was assigned,
750  // so assume it's reference set is unknown.
751  dest.insert(exprt(ID_unknown, object.type()));
752  }
753  else
754  {
755  object_mapt omt;
756  flatten(vit->second, omt);
757 
758  for(object_map_dt::iterator t_it=omt.write().begin();
759  t_it!=omt.write().end();
760  t_it++)
761  {
762  if(t_it->second && object_entry.second)
763  {
764  *t_it->second += *object_entry.second;
765  }
766  else
767  t_it->second.reset();
768  }
769 
770  for(const auto &o : omt.read())
771  dest.insert(to_expr(o));
772  }
773  }
774  else
775  dest.insert(to_expr(object_entry));
776  }
777 }
778 
780  const exprt &expr,
781  expr_sett &dest,
782  const namespacet &ns) const
783 {
784  object_mapt object_map;
785  get_reference_set_sharing(expr, object_map, ns);
786 
787  for(const auto &object_entry : object_map.read())
788  dest.insert(to_expr(object_entry));
789 }
790 
792  const exprt &expr,
793  object_mapt &dest,
794  const namespacet &ns) const
795 {
796  #if 0
797  std::cout << "GET_REFERENCE_SET_REC EXPR: " << format(expr)
798  << '\n';
799  #endif
800 
801  if(expr.type().id()=="#REF#")
802  {
803  valuest::const_iterator fi = values.find(expr.get(ID_identifier));
804  if(fi!=values.end())
805  {
806  for(const auto &object_entry : fi->second.object_map.read())
807  {
809  object_numbering[object_entry.first], dest, ns);
810  }
811  return;
812  }
813  }
814  else if(expr.id()==ID_symbol ||
815  expr.id()==ID_dynamic_object ||
816  expr.id()==ID_string_constant)
817  {
818  if(
819  expr.type().id() == ID_array &&
820  to_array_type(expr.type()).element_type().id() == ID_array)
821  {
822  insert(dest, expr);
823  }
824  else
825  insert(dest, expr, mp_integer{0});
826 
827  return;
828  }
829  else if(expr.id()==ID_dereference)
830  {
831  gvs_recursion_sett recset;
832  object_mapt temp;
833  bool includes_nondet_pointer = false;
835  to_dereference_expr(expr).pointer(),
836  temp,
837  includes_nondet_pointer,
838  "",
839  to_dereference_expr(expr).pointer().type(),
840  ns,
841  recset);
842 
843  // REF's need to be dereferenced manually!
844  for(const auto &object_entry : temp.read())
845  {
846  const exprt &obj = object_numbering[object_entry.first];
847  if(obj.type().id()=="#REF#")
848  {
849  const irep_idt &ident = obj.get(ID_identifier);
850  valuest::const_iterator v_it = values.find(ident);
851 
852  if(v_it!=values.end())
853  {
854  object_mapt t2;
855  flatten(v_it->second, t2);
856 
857  for(object_map_dt::iterator t_it=t2.write().begin();
858  t_it!=t2.write().end();
859  t_it++)
860  {
861  if(t_it->second && object_entry.second)
862  {
863  *t_it->second += *object_entry.second;
864  }
865  else
866  t_it->second.reset();
867  }
868 
869  for(const auto &t2_object_entry : t2.read())
870  insert(dest, t2_object_entry);
871  }
872  else
873  insert(
874  dest,
875  exprt(ID_unknown, to_type_with_subtype(obj.type()).subtype()));
876  }
877  else
878  insert(dest, object_entry);
879  }
880 
881  #if 0
882  for(expr_sett::const_iterator it=value_set.begin();
883  it!=value_set.end();
884  it++)
885  std::cout << "VALUE_SET: " << format(*it) << '\n';
886  #endif
887 
888  return;
889  }
890  else if(expr.id()==ID_index)
891  {
892  const exprt &array = to_index_expr(expr).array();
893  const exprt &offset = to_index_expr(expr).index();
894  const typet &array_type = array.type();
895 
897  array_type.id() == ID_array, "index takes array-typed operand");
898 
899  object_mapt array_references;
900  get_reference_set_sharing(array, array_references, ns);
901 
902  const object_map_dt &object_map=array_references.read();
903 
904  for(const auto &object_entry : object_map)
905  {
906  const exprt &object = object_numbering[object_entry.first];
907 
908  if(object.id()==ID_unknown)
909  insert(dest, exprt(ID_unknown, expr.type()));
910  else
911  {
912  index_exprt index_expr(
913  object, from_integer(0, c_index_type()), expr.type());
914 
915  exprt casted_index;
916 
917  // adjust type?
918  if(object.type().id() != "#REF#" && object.type() != array_type)
919  casted_index = typecast_exprt(index_expr, array.type());
920  else
921  casted_index = index_expr;
922 
923  offsett o = object_entry.second;
924  const auto i = numeric_cast<mp_integer>(offset);
925 
926  if(offset.is_zero())
927  {
928  }
929  else if(i.has_value() && offset_is_zero(o))
930  *o = *i;
931  else
932  o.reset();
933 
934  insert(dest, casted_index, o);
935  }
936  }
937 
938  return;
939  }
940  else if(expr.id()==ID_member)
941  {
942  const irep_idt &component_name=expr.get(ID_component_name);
943 
944  const exprt &struct_op = to_member_expr(expr).compound();
945 
946  object_mapt struct_references;
947  get_reference_set_sharing(struct_op, struct_references, ns);
948 
949  for(const auto &object_entry : struct_references.read())
950  {
951  const exprt &object = object_numbering[object_entry.first];
952  const typet &obj_type = object.type();
953 
954  if(object.id()==ID_unknown)
955  insert(dest, exprt(ID_unknown, expr.type()));
956  else if(
957  obj_type.id() != ID_struct && obj_type.id() != ID_union &&
958  obj_type.id() != ID_struct_tag && obj_type.id() != ID_union_tag)
959  {
960  // we catch objects of the wrong type,
961  // to avoid non-integral typecasts.
962  insert(dest, exprt(ID_unknown, expr.type()));
963  }
964  else
965  {
966  offsett o = object_entry.second;
967 
968  member_exprt member_expr(object, component_name, expr.type());
969 
970  // adjust type?
971  if(ns.follow(struct_op.type())!=ns.follow(object.type()))
972  {
973  member_expr.compound() =
974  typecast_exprt(member_expr.compound(), struct_op.type());
975  }
976 
977  insert(dest, member_expr, o);
978  }
979  }
980 
981  return;
982  }
983  else if(expr.id()==ID_if)
984  {
985  get_reference_set_sharing_rec(to_if_expr(expr).true_case(), dest, ns);
986  get_reference_set_sharing_rec(to_if_expr(expr).false_case(), dest, ns);
987  return;
988  }
989 
990  insert(dest, exprt(ID_unknown, expr.type()));
991 }
992 
994  const exprt &lhs,
995  const exprt &rhs,
996  const namespacet &ns)
997 {
998  #if 0
999  std::cout << "ASSIGN LHS: " << format(lhs) << '\n';
1000  std::cout << "ASSIGN RHS: " << format(rhs) << '\n';
1001  #endif
1002 
1003  if(rhs.id()==ID_if)
1004  {
1005  assign(lhs, to_if_expr(rhs).true_case(), ns);
1006  assign(lhs, to_if_expr(rhs).false_case(), ns);
1007  return;
1008  }
1009 
1010  const typet &type=ns.follow(lhs.type());
1011 
1012  if(type.id()==ID_struct ||
1013  type.id()==ID_union)
1014  {
1015  const struct_union_typet &struct_type=to_struct_union_type(type);
1016 
1017  std::size_t no=0;
1018 
1019  for(struct_typet::componentst::const_iterator
1020  c_it=struct_type.components().begin();
1021  c_it!=struct_type.components().end();
1022  c_it++, no++)
1023  {
1024  const typet &subtype=c_it->type();
1025  const irep_idt &name = c_it->get_name();
1026 
1027  // ignore padding
1029  subtype.id() != ID_code,
1030  "struct/union member must not be of code type");
1031  if(c_it->get_is_padding())
1032  continue;
1033 
1034  member_exprt lhs_member(lhs, name, subtype);
1035 
1036  exprt rhs_member;
1037 
1038  if(rhs.id()==ID_unknown ||
1039  rhs.id()==ID_invalid)
1040  {
1041  rhs_member=exprt(rhs.id(), subtype);
1042  }
1043  else
1044  {
1045  if(rhs.type() != lhs.type())
1046  throw "value_set_fit::assign type mismatch: "
1047  "rhs.type():\n"+rhs.type().pretty()+"\n"+
1048  "type:\n"+lhs.type().pretty();
1049 
1050  if(rhs.id() == ID_struct || rhs.is_constant())
1051  {
1053  no < rhs.operands().size(), "component index must be in bounds");
1054  rhs_member=rhs.operands()[no];
1055  }
1056  else if(rhs.id()==ID_with)
1057  {
1058  // see if this is the member we want
1059  const auto &rhs_with = to_with_expr(rhs);
1060  const exprt &member_operand = rhs_with.where();
1061 
1062  const irep_idt &component_name=
1063  member_operand.get(ID_component_name);
1064 
1065  if(component_name==name)
1066  {
1067  // yes! just take op2
1068  rhs_member = rhs_with.new_value();
1069  }
1070  else
1071  {
1072  // no! do op0
1073  rhs_member=exprt(ID_member, subtype);
1074  rhs_member.copy_to_operands(rhs_with.old());
1075  rhs_member.set(ID_component_name, name);
1076  }
1077  }
1078  else
1079  {
1080  rhs_member=exprt(ID_member, subtype);
1081  rhs_member.copy_to_operands(rhs);
1082  rhs_member.set(ID_component_name, name);
1083  }
1084 
1085  assign(lhs_member, rhs_member, ns);
1086  }
1087  }
1088  }
1089  else if(type.id()==ID_array)
1090  {
1091  const index_exprt lhs_index(
1092  lhs,
1093  exprt(ID_unknown, c_index_type()),
1094  to_array_type(type).element_type());
1095 
1096  if(rhs.id()==ID_unknown ||
1097  rhs.id()==ID_invalid)
1098  {
1099  assign(
1100  lhs_index, exprt(rhs.id(), to_array_type(type).element_type()), ns);
1101  }
1102  else if(rhs.is_nil())
1103  {
1104  // do nothing
1105  }
1106  else
1107  {
1108  if(rhs.type() != type)
1109  throw "value_set_fit::assign type mismatch: "
1110  "rhs.type():\n"+rhs.type().pretty()+"\n"+
1111  "type:\n"+type.pretty();
1112 
1113  if(rhs.id()==ID_array_of)
1114  {
1115  assign(lhs_index, to_array_of_expr(rhs).what(), ns);
1116  }
1117  else if(rhs.id() == ID_array || rhs.is_constant())
1118  {
1119  for(const auto &op : rhs.operands())
1120  {
1121  assign(lhs_index, op, ns);
1122  }
1123  }
1124  else if(rhs.id()==ID_with)
1125  {
1126  const index_exprt op0_index(
1127  to_with_expr(rhs).old(),
1128  exprt(ID_unknown, c_index_type()),
1129  to_array_type(type).element_type());
1130 
1131  assign(lhs_index, op0_index, ns);
1132  assign(lhs_index, to_with_expr(rhs).new_value(), ns);
1133  }
1134  else
1135  {
1136  const index_exprt rhs_index(
1137  rhs,
1138  exprt(ID_unknown, c_index_type()),
1139  to_array_type(type).element_type());
1140  assign(lhs_index, rhs_index, ns);
1141  }
1142  }
1143  }
1144  else
1145  {
1146  // basic type
1147  object_mapt values_rhs;
1148 
1149  get_value_set(rhs, values_rhs, ns);
1150 
1151  assign_recursion_sett recset;
1152  assign_rec(lhs, values_rhs, "", ns, recset);
1153  }
1154 }
1155 
1157  const exprt &lhs,
1158  const object_mapt &values_rhs,
1159  const std::string &suffix,
1160  const namespacet &ns,
1161  assign_recursion_sett &recursion_set)
1162 {
1163  #if 0
1164  std::cout << "ASSIGN_REC LHS: " << format(lhs) << '\n';
1165  std::cout << "ASSIGN_REC SUFFIX: " << suffix << '\n';
1166 
1167  for(object_map_dt::const_iterator it=values_rhs.read().begin();
1168  it!=values_rhs.read().end(); it++)
1169  std::cout << "ASSIGN_REC RHS: " << to_expr(it) << '\n';
1170  #endif
1171 
1172  if(lhs.type().id()=="#REF#")
1173  {
1174  const irep_idt &ident = lhs.get(ID_identifier);
1175  object_mapt temp;
1176  gvs_recursion_sett recset;
1177  bool includes_nondet_pointer = false;
1179  lhs,
1180  temp,
1181  includes_nondet_pointer,
1182  "",
1184  ns,
1185  recset);
1186 
1187  if(recursion_set.find(ident)!=recursion_set.end())
1188  {
1189  recursion_set.insert(ident);
1190 
1191  for(const auto &object_entry : temp.read())
1192  {
1193  const exprt &object = object_numbering[object_entry.first];
1194 
1195  if(object.id() != ID_unknown)
1196  assign_rec(object, values_rhs, suffix, ns, recursion_set);
1197  }
1198 
1199  recursion_set.erase(ident);
1200  }
1201  }
1202  else if(lhs.id()==ID_symbol)
1203  {
1204  const irep_idt &identifier = to_symbol_expr(lhs).get_identifier();
1205 
1206  if(
1207  identifier.starts_with("value_set::dynamic_object") ||
1208  identifier.starts_with("value_set::return_value") ||
1209  values.find(id2string(identifier) + suffix) != values.end())
1210  // otherwise we don't track this value
1211  {
1212  entryt &entry = get_entry(identifier, suffix);
1213 
1214  if(make_union(entry.object_map, values_rhs))
1215  changed = true;
1216  }
1217  }
1218  else if(lhs.id()==ID_dynamic_object)
1219  {
1220  const dynamic_object_exprt &dynamic_object=
1222 
1223  const std::string name=
1224  "value_set::dynamic_object"+
1225  std::to_string(dynamic_object.get_instance());
1226 
1227  if(make_union(get_entry(name, suffix).object_map, values_rhs))
1228  changed = true;
1229  }
1230  else if(lhs.id()==ID_dereference)
1231  {
1232  if(lhs.operands().size()!=1)
1233  throw lhs.id_string()+" expected to have one operand";
1234 
1235  object_mapt reference_set;
1236  get_reference_set_sharing(lhs, reference_set, ns);
1237 
1238  for(const auto &object_entry : reference_set.read())
1239  {
1240  const exprt &object = object_numbering[object_entry.first];
1241 
1242  if(object.id()!=ID_unknown)
1243  assign_rec(object, values_rhs, suffix, ns, recursion_set);
1244  }
1245  }
1246  else if(lhs.id()==ID_index)
1247  {
1248  const typet &type = to_index_expr(lhs).array().type();
1249 
1250  if(type.id() == ID_array)
1251  {
1252  assign_rec(
1253  to_index_expr(lhs).array(),
1254  values_rhs,
1255  "[]" + suffix,
1256  ns,
1257  recursion_set);
1258  }
1259  }
1260  else if(lhs.id()==ID_member)
1261  {
1262  if(to_member_expr(lhs).compound().is_nil())
1263  return;
1264 
1265  const std::string &component_name=lhs.get_string(ID_component_name);
1266 
1267  const typet &type = ns.follow(to_member_expr(lhs).compound().type());
1268 
1270  type.id() == ID_struct || type.id() == ID_union,
1271  "operand 0 of member expression must be struct or union");
1272 
1273  assign_rec(
1274  to_member_expr(lhs).compound(),
1275  values_rhs,
1276  "." + component_name + suffix,
1277  ns,
1278  recursion_set);
1279  }
1280  else if(lhs.id()=="valid_object" ||
1281  lhs.id()=="dynamic_type")
1282  {
1283  // we ignore this here
1284  }
1285  else if(lhs.id()==ID_string_constant)
1286  {
1287  // someone writes into a string-constant
1288  // evil guy
1289  }
1290  else if(lhs.id() == ID_null_object)
1291  {
1292  // evil as well
1293  }
1294  else if(lhs.id()==ID_typecast)
1295  {
1296  const typecast_exprt &typecast_expr=to_typecast_expr(lhs);
1297 
1298  assign_rec(typecast_expr.op(), values_rhs, suffix, ns, recursion_set);
1299  }
1300  else if(
1301  lhs.id() == "zero_string" || lhs.id() == "is_zero_string" ||
1302  lhs.id() == "zero_string_length" || lhs.id() == ID_address_of)
1303  {
1304  // ignore
1305  }
1306  else if(lhs.id()==ID_byte_extract_little_endian ||
1307  lhs.id()==ID_byte_extract_big_endian)
1308  {
1309  assign_rec(
1310  to_byte_extract_expr(lhs).op(), values_rhs, suffix, ns, recursion_set);
1311  }
1312  else
1313  throw "assign NYI: '" + lhs.id_string() + "'";
1314 }
1315 
1317  const irep_idt &function,
1318  const exprt::operandst &arguments,
1319  const namespacet &ns)
1320 {
1321  const symbolt &symbol=ns.lookup(function);
1322 
1323  const code_typet &type=to_code_type(symbol.type);
1324  const code_typet::parameterst &parameter_types=type.parameters();
1325 
1326  // these first need to be assigned to dummy, temporary arguments
1327  // and only thereafter to the actuals, in order
1328  // to avoid overwriting actuals that are needed for recursive
1329  // calls
1330 
1331  for(std::size_t i=0; i<arguments.size(); i++)
1332  {
1333  const std::string identifier="value_set::" + id2string(function) + "::" +
1334  "argument$"+std::to_string(i);
1335  add_var(identifier);
1336  const symbol_exprt dummy_lhs(identifier, arguments[i].type());
1337  assign(dummy_lhs, arguments[i], ns);
1338  }
1339 
1340  // now assign to 'actual actuals'
1341 
1342  std::size_t i=0;
1343 
1344  for(code_typet::parameterst::const_iterator
1345  it=parameter_types.begin();
1346  it!=parameter_types.end();
1347  it++)
1348  {
1349  const irep_idt &identifier=it->get_identifier();
1350  if(identifier.empty())
1351  continue;
1352 
1353  add_var(identifier);
1354 
1355  const exprt v_expr=
1356  symbol_exprt("value_set::" + id2string(function) + "::" +
1357  "argument$"+std::to_string(i), it->type());
1358 
1359  const symbol_exprt actual_lhs(identifier, it->type());
1360  assign(actual_lhs, v_expr, ns);
1361  i++;
1362  }
1363 }
1364 
1366  const exprt &lhs,
1367  const namespacet &ns)
1368 {
1369  if(lhs.is_nil())
1370  return;
1371 
1372  std::string rvs = "value_set::return_value" + std::to_string(from_function);
1373  symbol_exprt rhs(rvs, lhs.type());
1374 
1375  assign(lhs, rhs, ns);
1376 }
1377 
1378 void value_set_fit::apply_code(const codet &code, const namespacet &ns)
1379 {
1380  const irep_idt &statement=code.get(ID_statement);
1381 
1382  if(statement==ID_block)
1383  {
1384  for(const auto &stmt : to_code_block(code).statements())
1385  apply_code(stmt, ns);
1386  }
1387  else if(statement==ID_function_call)
1388  {
1389  // shouldn't be here
1390  UNREACHABLE;
1391  }
1392  else if(statement==ID_assign)
1393  {
1394  if(code.operands().size()!=2)
1395  throw "assignment expected to have two operands";
1396 
1397  assign(code.op0(), code.op1(), ns);
1398  }
1399  else if(statement==ID_decl)
1400  {
1401  if(code.operands().size()!=1)
1402  throw "decl expected to have one operand";
1403 
1404  const exprt &lhs=code.op0();
1405 
1406  if(lhs.id()!=ID_symbol)
1407  throw "decl expected to have symbol on lhs";
1408 
1409  assign(lhs, exprt(ID_invalid, lhs.type()), ns);
1410  }
1411  else if(statement==ID_expression)
1412  {
1413  // can be ignored, we don't expect side effects here
1414  }
1415  else if(statement==ID_cpp_delete ||
1416  statement==ID_cpp_delete_array)
1417  {
1418  // does nothing
1419  }
1420  else if(statement=="lock" || statement=="unlock")
1421  {
1422  // ignore for now
1423  }
1424  else if(statement==ID_asm)
1425  {
1426  // ignore for now, probably not safe
1427  }
1428  else if(statement==ID_nondet)
1429  {
1430  // doesn't do anything
1431  }
1432  else if(statement==ID_printf)
1433  {
1434  // doesn't do anything
1435  }
1436  else if(statement==ID_return)
1437  {
1438  const code_returnt &code_return = to_code_return(code);
1439  // this is turned into an assignment
1440  std::string rvs = "value_set::return_value" + std::to_string(from_function);
1441  symbol_exprt lhs(rvs, code_return.return_value().type());
1442  assign(lhs, code_return.return_value(), ns);
1443  }
1444  else if(statement==ID_fence)
1445  {
1446  }
1447  else if(
1448  statement == ID_array_copy || statement == ID_array_replace ||
1449  statement == ID_array_set || statement == ID_array_equal)
1450  {
1451  }
1453  {
1454  // doesn't do anything
1455  }
1456  else if(statement == ID_havoc_object)
1457  {
1458  }
1459  else
1460  throw
1461  code.pretty()+"\n"+
1462  "value_set_fit: unexpected statement: "+id2string(statement);
1463 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Expression classes for byte-level operators.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
bitvector_typet c_index_type()
Definition: c_types.cpp:16
Operator to return the address of an object.
Definition: pointer_expr.h:540
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:827
goto_instruction_codet representation of a "return from a function" statement.
const exprt & return_value() const
Base type of functions.
Definition: std_types.h:583
std::vector< parametert > parameterst
Definition: std_types.h:585
const parameterst & parameters() const
Definition: std_types.h:699
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:29
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool starts_with(const char *s) const
equivalent of as_string().starts_with(s)
Definition: dstring.h:95
bool empty() const
Definition: dstring.h:89
void clear()
Definition: dstring.h:159
Representation of heap-allocated objects.
Definition: pointer_expr.h:272
unsigned int get_instance() const
void set_instance(unsigned int instance)
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition: expr.h:163
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition: expr.cpp:47
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
operandst & operands()
Definition: expr.h:94
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
exprt & index()
Definition: std_expr.h:1505
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
const std::string & id_string() const
Definition: irep.h:387
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:408
const irep_idt & id() const
Definition: irep.h:384
const std::string & get_string(const irep_idt &name) const
Definition: irep.h:397
bool is_nil() const
Definition: irep.h:364
Extract member of struct or union.
Definition: std_expr.h:2841
const exprt & compound() const
Definition: std_expr.h:2890
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
Split an expression into a base object and a (byte) offset.
Definition: pointer_expr.h:181
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
const T & read() const
const irep_idt & get_statement() const
Definition: std_code.h:1472
Base type for structs and unions.
Definition: std_types.h:62
const componentst & components() const
Definition: std_types.h:147
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
Symbol table entry.
Definition: symbol.h:28
const irep_idt & display_name() const
Return language specific display name if present.
Definition: symbol.h:55
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
The Boolean constant true.
Definition: std_expr.h:3055
Type with a single subtype.
Definition: type.h:180
const typet & subtype() const
Definition: type.h:187
Semantic type conversion.
Definition: std_expr.h:2068
The type of an expression, extends irept.
Definition: type.h:29
const exprt & op() const
Definition: std_expr.h:391
data_typet::value_type value_type
Definition: value_set_fi.h:77
data_typet::const_iterator const_iterator
Definition: value_set_fi.h:75
static const object_map_dt blank
Definition: value_set_fi.h:100
data_typet::iterator iterator
Definition: value_set_fi.h:73
std::optional< mp_integer > offsett
Represents the offset into an object: either a unique integer offset, or an unknown value,...
Definition: value_set_fi.h:60
void get_reference_set_sharing(const exprt &expr, expr_sett &expr_set, const namespacet &ns) const
static object_numberingt object_numbering
Definition: value_set_fi.h:41
void get_reference_set(const exprt &expr, expr_sett &expr_set, const namespacet &ns) const
void assign(const exprt &lhs, const exprt &rhs, const namespacet &ns)
static numberingt< irep_idt > function_numbering
Definition: value_set_fi.h:42
void add_var(const idt &id)
Definition: value_set_fi.h:212
std::unordered_set< idt > assign_recursion_sett
Definition: value_set_fi.h:198
entryt & get_entry(const idt &id, const std::string &suffix)
Definition: value_set_fi.h:222
valuest values
Definition: value_set_fi.h:250
bool make_union(object_mapt &dest, const object_mapt &src) const
std::vector< exprt > get_value_set(const exprt &expr, const namespacet &ns) const
unsigned from_function
Definition: value_set_fi.h:39
void apply_code(const codet &code, const namespacet &ns)
void get_value_set_rec(const exprt &expr, object_mapt &dest, bool &includes_nondet_pointer, const std::string &suffix, const typet &original_type, const namespacet &ns, gvs_recursion_sett &recursion_set) const
void assign_rec(const exprt &lhs, const object_mapt &values_rhs, const std::string &suffix, const namespacet &ns, assign_recursion_sett &recursion_set)
void dereference_rec(const exprt &src, exprt &dest) const
void output(const namespacet &ns, std::ostream &out) const
void flatten_rec(const entryt &, object_mapt &, flatten_seent &) const
std::unordered_set< exprt, irep_hash > expr_sett
Definition: value_set_fi.h:190
void do_end_function(const exprt &lhs, const namespacet &ns)
std::set< idt > flatten_seent
Definition: value_set_fi.h:195
void flatten(const entryt &e, object_mapt &dest) const
bool offset_is_zero(const offsett &offset) const
Definition: value_set_fi.h:61
unsigned from_target_index
Definition: value_set_fi.h:40
bool insert(object_mapt &dest, const object_map_dt::value_type &it) const
Definition: value_set_fi.h:115
std::unordered_set< idt > gvs_recursion_sett
Definition: value_set_fi.h:196
std::map< idt, entryt > valuest
Definition: value_set_fi.h:194
exprt to_expr(const object_map_dt::value_type &it) const
void do_function_call(const irep_idt &function, const exprt::operandst &arguments, const namespacet &ns)
void get_reference_set_sharing_rec(const exprt &expr, object_mapt &dest, const namespacet &ns) const
bool is_null_pointer(const constant_exprt &expr)
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition: expr_util.cpp:369
Deprecated expression utility functions.
static format_containert< T > format(const T &o)
Definition: format.h:37
const code_returnt & to_code_return(const goto_instruction_codet &code)
bool can_cast_expr< code_inputt >(const exprt &base)
bool can_cast_expr< code_outputt >(const exprt &base)
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
std::string from_type(const namespacet &ns, const irep_idt &identifier, const typet &type)
const std::string integer2string(const mp_integer &n, unsigned base)
Definition: mp_arith.cpp:103
API to expression classes for Pointers.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:890
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const dynamic_object_exprt & to_dynamic_object_expr(const exprt &expr)
Cast an exprt to a dynamic_object_exprt.
Definition: pointer_expr.h:315
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
bool simplify(exprt &expr, const namespacet &ns)
BigInt mp_integer
Definition: smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition: std_code.h:1506
const code_blockt & to_code_block(const codet &code)
Definition: std_code.h:203
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2450
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3037
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition: std_expr.h:2533
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:715
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition: std_expr.h:1598
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2933
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
object_mapt object_map
Definition: value_set_fi.h:175
Symbol table entry.
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208
static const char * alloc_adapter_prefix
Value Set (Flow Insensitive, Sharing)