CBMC
Loading...
Searching...
No Matches
goto_program.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Program Transformation
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "goto_program.h"
13
14#include <util/expr_iterator.h>
15#include <util/find_symbols.h>
16#include <util/format_expr.h>
17#include <util/format_type.h>
18#include <util/invariant.h>
19#include <util/namespace.h>
20#include <util/pointer_expr.h>
21#include <util/std_code.h>
22#include <util/std_expr.h>
23#include <util/symbol.h>
24#include <util/validate.h>
25
27
28#include "validate_code.h"
29
30#include <iomanip>
31#include <map>
32
39
49std::ostream &goto_programt::instructiont::output(std::ostream &out) const
50{
51 out << " // " << location_number << " ";
52
53 if(!source_location().is_nil())
54 out << source_location().as_string();
55 else
56 out << "no location";
57
58 out << "\n";
59
60 if(!labels.empty())
61 {
62 out << " // Labels:";
63 for(const auto &label : labels)
64 out << " " << label;
65
66 out << '\n';
67 }
68
69 if(is_target())
70 out << std::setw(6) << target_number << ": ";
71 else
72 out << " ";
73
74 switch(type())
75 {
77 out << "NO INSTRUCTION TYPE SET" << '\n';
78 break;
79
80 case GOTO:
81 case INCOMPLETE_GOTO:
82 if(!condition().is_true())
83 {
84 out << "IF " << format(condition()) << " THEN ";
85 }
86
87 out << "GOTO ";
88
90 {
91 out << "(incomplete)";
92 }
93 else
94 {
95 for(auto gt_it = targets.begin(); gt_it != targets.end(); gt_it++)
96 {
97 if(gt_it != targets.begin())
98 out << ", ";
99 out << (*gt_it)->target_number;
100 }
101 }
102
103 out << '\n';
104 break;
105
106 case OTHER:
107 if(get_other().id() == ID_code)
108 {
109 const auto &code = get_other();
110 if(code.get_statement() == ID_array_copy)
111 {
112 out << "ARRAY_COPY " << format(code.op0()) << ' ' << format(code.op1())
113 << '\n';
114 break;
115 }
116 else if(code.get_statement() == ID_array_replace)
117 {
118 out << "ARRAY_REPLACE " << format(code.op0()) << ' '
119 << format(code.op1()) << '\n';
120 break;
121 }
122 else if(code.get_statement() == ID_array_set)
123 {
124 out << "ARRAY_SET " << format(code.op0()) << ' ' << format(code.op1())
125 << '\n';
126 break;
127 }
128 else if(code.get_statement() == ID_expression)
129 {
130 out << "EXPRESSION " << format(code.op0()) << '\n';
131 break;
132 }
133 else if(code.get_statement() == ID_havoc_object)
134 {
135 out << "HAVOC_OBJECT " << format(code.op0()) << '\n';
136 break;
137 }
138 else if(code.get_statement() == ID_fence)
139 {
140 out << "FENCE";
141 if(code.get_bool(ID_WWfence))
142 out << " WW";
143 if(code.get_bool(ID_RRfence))
144 out << " RR";
145 if(code.get_bool(ID_RWfence))
146 out << " RW";
147 if(code.get_bool(ID_WRfence))
148 out << " WR";
149 out << '\n';
150 break;
151 }
152 else if(code.get_statement() == ID_input)
153 {
154 out << "INPUT";
155 for(const auto &op : code.operands())
156 out << ' ' << format(op);
157 out << '\n';
158 break;
159 }
160 else if(code.get_statement() == ID_output)
161 {
162 out << "OUTPUT " << format(code.op0()) << '\n';
163 break;
164 }
165 // fallthrough
166 }
167
168 out << "OTHER " << format(get_other()) << '\n';
169 break;
170
171 case SET_RETURN_VALUE:
172 out << "SET RETURN VALUE " << format(return_value()) << '\n';
173 break;
174
175 case DECL:
176 out << "DECL " << format(decl_symbol()) << " : "
177 << format(decl_symbol().type()) << '\n';
178 break;
179
180 case DEAD:
181 out << "DEAD " << format(dead_symbol()) << '\n';
182 break;
183
184 case FUNCTION_CALL:
185 out << "CALL ";
186 {
187 if(call_lhs().is_not_nil())
188 out << format(call_lhs()) << " := ";
189 out << format(call_function());
190 out << '(';
191 bool first = true;
192 for(const auto &argument : call_arguments())
193 {
194 if(first)
195 first = false;
196 else
197 out << ", ";
198 out << format(argument);
199 }
200 out << ')';
201 out << '\n';
202 }
203 break;
204
205 case ASSIGN:
206 out << "ASSIGN " << format(assign_lhs()) << " := " << format(assign_rhs())
207 << '\n';
208 break;
209
210 case ASSUME:
211 case ASSERT:
212 if(is_assume())
213 out << "ASSUME ";
214 else
215 out << "ASSERT ";
216
217 {
218 out << format(condition());
219
220 const irep_idt &comment = source_location().get_comment();
221 if(!comment.empty())
222 out << " // " << comment;
223 }
224
225 out << '\n';
226 break;
227
228 case SKIP:
229 out << "SKIP" << '\n';
230 break;
231
232 case END_FUNCTION:
233 out << "END_FUNCTION" << '\n';
234 break;
235
236 case LOCATION:
237 out << "LOCATION" << '\n';
238 break;
239
240 case THROW:
241 out << "THROW";
242
243 {
244 const irept::subt &exception_list =
245 code().find(ID_exception_list).get_sub();
246
247 for(const auto &ex : exception_list)
248 out << " " << ex.id();
249 }
250
251 if(code().operands().size() == 1)
252 out << ": " << format(code().op0());
253
254 out << '\n';
255 break;
256
257 case CATCH:
258 {
259 if(code().get_statement() == ID_exception_landingpad)
260 {
261 const auto &landingpad = to_code_landingpad(code());
262 out << "EXCEPTION LANDING PAD (" << format(landingpad.catch_expr().type())
263 << ' ' << format(landingpad.catch_expr()) << ")";
264 }
265 else if(code().get_statement() == ID_push_catch)
266 {
267 out << "CATCH-PUSH ";
268
269 unsigned i=0;
270 const irept::subt &exception_list =
271 code().find(ID_exception_list).get_sub();
273 targets.size() == exception_list.size(),
274 "unexpected discrepancy between sizes of instruction"
275 "targets and exception list");
276 for(instructiont::targetst::const_iterator gt_it = targets.begin();
277 gt_it != targets.end();
278 gt_it++, i++)
279 {
280 if(gt_it != targets.begin())
281 out << ", ";
282 out << exception_list[i].id() << "->"
283 << (*gt_it)->target_number;
284 }
285 }
286 else if(code().get_statement() == ID_pop_catch)
287 {
288 out << "CATCH-POP";
289 }
290 else
291 {
293 }
294
295 out << '\n';
296 break;
297 }
298
299 case ATOMIC_BEGIN:
300 out << "ATOMIC_BEGIN" << '\n';
301 break;
302
303 case ATOMIC_END:
304 out << "ATOMIC_END" << '\n';
305 break;
306
307 case START_THREAD:
308 out << "START THREAD " << get_target()->target_number << '\n';
309 break;
310
311 case END_THREAD:
312 out << "END THREAD" << '\n';
313 break;
314 }
315
316 return out;
317}
318
321{
322 for(const auto &instruction : instructions)
323 {
324 if(instruction.is_decl())
325 {
327 instruction.code().get_statement() == ID_decl,
328 "expected statement to be declaration statement");
330 instruction.code().operands().size() == 1,
331 "declaration statement expects one operand");
332 decl_identifiers.insert(instruction.decl_symbol().get_identifier());
333 }
334 }
335}
336
337void parse_lhs_read(const exprt &src, std::list<exprt> &dest)
338{
339 if(src.id()==ID_dereference)
340 {
341 dest.push_back(to_dereference_expr(src).pointer());
342 }
343 else if(src.id()==ID_index)
344 {
345 auto &index_expr = to_index_expr(src);
346 dest.push_back(index_expr.index());
347 parse_lhs_read(index_expr.array(), dest);
348 }
349 else if(src.id()==ID_member)
350 {
351 parse_lhs_read(to_member_expr(src).compound(), dest);
352 }
353 else if(src.id()==ID_if)
354 {
355 auto &if_expr = to_if_expr(src);
356 dest.push_back(if_expr.cond());
357 parse_lhs_read(if_expr.true_case(), dest);
358 parse_lhs_read(if_expr.false_case(), dest);
359 }
360}
361
362std::list<exprt> expressions_read(
363 const goto_programt::instructiont &instruction)
364{
365 std::list<exprt> dest;
366
367 switch(instruction.type())
368 {
369 case ASSUME:
370 case ASSERT:
371 case GOTO:
372 dest.push_back(instruction.condition());
373 break;
374
375 case SET_RETURN_VALUE:
376 dest.push_back(instruction.return_value());
377 break;
378
379 case FUNCTION_CALL:
380 for(const auto &argument : instruction.call_arguments())
381 dest.push_back(argument);
382 if(instruction.call_lhs().is_not_nil())
383 parse_lhs_read(instruction.call_lhs(), dest);
384 break;
385
386 case ASSIGN:
387 dest.push_back(instruction.assign_rhs());
388 parse_lhs_read(instruction.assign_lhs(), dest);
389 break;
390
391 case CATCH:
392 case THROW:
393 case DEAD:
394 case DECL:
395 case ATOMIC_BEGIN:
396 case ATOMIC_END:
397 case START_THREAD:
398 case END_THREAD:
399 case END_FUNCTION:
400 case LOCATION:
401 case SKIP:
402 case OTHER:
403 case INCOMPLETE_GOTO:
405 break;
406 }
407
408 return dest;
409}
410
411std::list<exprt> expressions_written(
412 const goto_programt::instructiont &instruction)
413{
414 std::list<exprt> dest;
415
416 switch(instruction.type())
417 {
418 case FUNCTION_CALL:
419 if(instruction.call_lhs().is_not_nil())
420 dest.push_back(instruction.call_lhs());
421 break;
422
423 case ASSIGN:
424 dest.push_back(instruction.assign_lhs());
425 break;
426
427 case CATCH:
428 case THROW:
429 case GOTO:
430 case SET_RETURN_VALUE:
431 case DEAD:
432 case DECL:
433 case ATOMIC_BEGIN:
434 case ATOMIC_END:
435 case START_THREAD:
436 case END_THREAD:
437 case END_FUNCTION:
438 case ASSERT:
439 case ASSUME:
440 case LOCATION:
441 case SKIP:
442 case OTHER:
443 case INCOMPLETE_GOTO:
445 break;
446 }
447
448 return dest;
449}
450
452 const exprt &src,
453 std::list<exprt> &dest)
454{
455 if(src.id()==ID_symbol)
456 dest.push_back(src);
457 else if(src.id()==ID_address_of)
458 {
459 // don't traverse!
460 }
461 else if(src.id()==ID_dereference)
462 {
463 // this reads what is pointed to plus the pointer
464 auto &deref = to_dereference_expr(src);
465 dest.push_back(deref);
466 objects_read(deref.pointer(), dest);
467 }
468 else
469 {
470 for(const auto &op : src.operands())
471 objects_read(op, dest);
472 }
473}
474
475std::list<exprt> objects_read(
476 const goto_programt::instructiont &instruction)
477{
478 std::list<exprt> expressions=expressions_read(instruction);
479
480 std::list<exprt> dest;
481
482 for(const auto &expr : expressions)
483 objects_read(expr, dest);
484
485 return dest;
486}
487
489 const exprt &src,
490 std::list<exprt> &dest)
491{
492 if(src.id()==ID_if)
493 {
494 auto &if_expr = to_if_expr(src);
495 objects_written(if_expr.true_case(), dest);
496 objects_written(if_expr.false_case(), dest);
497 }
498 else
499 dest.push_back(src);
500}
501
502std::list<exprt> objects_written(
503 const goto_programt::instructiont &instruction)
504{
505 std::list<exprt> expressions=expressions_written(instruction);
506
507 std::list<exprt> dest;
508
509 for(const auto &expr : expressions)
510 objects_written(expr, dest);
511
512 return dest;
513}
514
515std::string as_string(
516 const class namespacet &ns,
517 const irep_idt &function,
519{
520 std::string result;
521
522 switch(i.type())
523 {
525 return "(NO INSTRUCTION TYPE)";
526
527 case GOTO:
528 if(!i.condition().is_true())
529 {
530 result += "IF " + from_expr(ns, function, i.condition()) + " THEN ";
531 }
532
533 result+="GOTO ";
534
535 for(goto_programt::instructiont::targetst::const_iterator
536 gt_it=i.targets.begin();
537 gt_it!=i.targets.end();
538 gt_it++)
539 {
540 if(gt_it!=i.targets.begin())
541 result+=", ";
542 result+=std::to_string((*gt_it)->target_number);
543 }
544 return result;
545
546 case SET_RETURN_VALUE:
547 case OTHER:
548 case DECL:
549 case DEAD:
550 case FUNCTION_CALL:
551 case ASSIGN:
552 return from_expr(ns, function, i.code());
553
554 case ASSUME:
555 case ASSERT:
556 if(i.is_assume())
557 result+="ASSUME ";
558 else
559 result+="ASSERT ";
560
561 result += from_expr(ns, function, i.condition());
562
563 {
564 const irep_idt &comment = i.source_location().get_comment();
565 if(!comment.empty())
566 result+=" /* "+id2string(comment)+" */";
567 }
568 return result;
569
570 case SKIP:
571 return "SKIP";
572
573 case END_FUNCTION:
574 return "END_FUNCTION";
575
576 case LOCATION:
577 return "LOCATION";
578
579 case THROW:
580 return "THROW";
581
582 case CATCH:
583 return "CATCH";
584
585 case ATOMIC_BEGIN:
586 return "ATOMIC_BEGIN";
587
588 case ATOMIC_END:
589 return "ATOMIC_END";
590
591 case START_THREAD:
592 result+="START THREAD ";
593
594 if(i.targets.size()==1)
595 result+=std::to_string(i.targets.front()->target_number);
596 return result;
597
598 case END_THREAD:
599 return "END THREAD";
600
601 case INCOMPLETE_GOTO:
603 }
604
606}
607
612{
613 unsigned nr=0;
614 for(auto &i : instructions)
615 if(i.is_backwards_goto())
616 i.loop_number=nr++;
617}
618
626
627std::ostream &goto_programt::output(std::ostream &out) const
628{
629 // output the program
630
631 for(const auto &instruction : instructions)
632 instruction.output(out);
633
634 return out;
635}
636
648{
649 // reset marking
650
651 for(auto &i : instructions)
652 i.target_number=instructiont::nil_target;
653
654 // mark the goto targets
655
656 for(const auto &i : instructions)
657 {
658 for(const auto &t : i.targets)
659 {
660 if(t!=instructions.end())
661 t->target_number=0;
662 }
663 }
664
665 // number the targets properly
666 unsigned cnt=0;
667
668 for(auto &i : instructions)
669 {
670 if(i.is_target())
671 {
672 i.target_number=++cnt;
674 i.target_number != 0, "GOTO instruction target cannot be zero");
675 }
676 }
677
678 // check the targets!
679 // (this is a consistency check only)
680
681 for(const auto &i : instructions)
682 {
683 for(const auto &t : i.targets)
684 {
685 if(t!=instructions.end())
686 {
688 t->target_number != 0, "instruction's number cannot be zero");
690 t->target_number != instructiont::nil_target,
691 "GOTO instruction target cannot be nil_target");
692 }
693 }
694 }
695}
696
702{
703 // Definitions for mapping between the two programs
704 typedef std::map<const_targett, targett, target_less_than> targets_mappingt;
706
707 clear();
708
709 // Loop over program - 1st time collects targets and copy
710
711 for(instructionst::const_iterator
712 it=src.instructions.begin();
713 it!=src.instructions.end();
714 ++it)
715 {
716 auto new_instruction=add_instruction();
717 targets_mapping[it]=new_instruction;
718 *new_instruction=*it;
719 }
720
721 // Loop over program - 2nd time updates targets
722
723 for(auto &i : instructions)
724 {
725 for(auto &t : i.targets)
726 {
727 targets_mappingt::iterator
729
731
732 t=m_target_it->second;
733 }
734 }
735
738}
739
743{
744 for(const auto &i : instructions)
745 if(i.is_assert() && !i.condition().is_true())
746 return true;
747
748 return false;
749}
750
753{
754 for(auto &i : instructions)
755 {
756 i.incoming_edges.clear();
757 }
758
759 for(instructionst::iterator
760 it=instructions.begin();
761 it!=instructions.end();
762 ++it)
763 {
764 for(const auto &s : get_successors(it))
765 {
766 if(s!=instructions.end())
767 s->incoming_edges.insert(it);
768 }
769 }
770}
771
773{
774 // clang-format off
775 return
776 _type == other._type &&
777 _code == other._code &&
778 guard == other.guard &&
779 targets.size() == other.targets.size() &&
780 labels == other.labels;
781 // clang-format on
782}
783
785 const namespacet &ns,
786 const validation_modet vm) const
787{
788 validate_full_code(_code, ns, vm);
789 validate_full_expr(guard, ns, vm);
790
791 auto expr_symbol_finder = [&](const exprt &e) {
794 const symbolt *symbol;
795 for(const auto &identifier : typetags)
796 {
798 vm,
799 !ns.lookup(identifier, symbol),
800 id2string(identifier) + " not found",
801 source_location());
802 }
803 };
804
805 auto &current_source_location = source_location();
806 auto type_finder =
807 [&ns, vm, &current_source_location](const exprt &e) {
808 if(e.id() == ID_symbol)
809 {
810 const auto &goto_symbol_expr = to_symbol_expr(e);
811 const auto &goto_id = goto_symbol_expr.get_identifier();
812
813 const symbolt *table_symbol;
814 if(!ns.lookup(goto_id, table_symbol))
815 {
817 goto_symbol_expr.type() == table_symbol->type;
818
819 if(
821 table_symbol->type.id() == ID_code)
822 {
823 // If a function declaration and its definition are in different
824 // translation units they may have different return types.
825 // Thus, the return type in the symbol table may differ
826 // from the return type in the symbol expr.
827 if(
828 goto_symbol_expr.type().source_location().get_file() !=
829 table_symbol->type.source_location().get_file())
830 {
831 // temporarily fixup the return types
835
836 goto_symbol_expr_type.return_type() =
837 table_symbol_type.return_type();
838
841 }
842 }
843
844 if(
846 goto_symbol_expr.type().id() == ID_array &&
847 to_array_type(goto_symbol_expr.type()).is_incomplete())
848 {
849 // If the symbol expr has an incomplete array type, it may not have
850 // a constant size value, whereas the symbol table entry may have
851 // an (assumed) constant size of 1 (which mimics gcc behaviour)
852 if(table_symbol->type.id() == ID_array)
853 {
856
859 }
860 }
861
863 vm,
865 id2string(goto_id) + " type inconsistency\n" +
866 "goto program type: " + goto_symbol_expr.type().id_string() +
867 "\n" + "symbol table type: " + table_symbol->type.id_string(),
869 }
870 }
871 };
872
873 const symbolt *table_symbol;
874 switch(_type)
875 {
877 break;
878 case GOTO:
880 vm,
881 has_target(),
882 "goto instruction expects at least one target",
883 source_location());
884 // get_target checks that targets.size()==1
886 vm,
887 get_target()->is_target() && get_target()->target_number != 0,
888 "goto target has to be a target",
889 source_location());
890 break;
891 case ASSUME:
893 vm,
894 targets.empty(),
895 "assume instruction should not have a target",
896 source_location());
897 break;
898 case ASSERT:
900 vm,
901 targets.empty(),
902 "assert instruction should not have a target",
903 source_location());
904
906 std::for_each(guard.depth_begin(), guard.depth_end(), type_finder);
907 break;
908 case OTHER:
909 break;
910 case SKIP:
911 break;
912 case START_THREAD:
913 break;
914 case END_THREAD:
915 break;
916 case LOCATION:
917 break;
918 case END_FUNCTION:
919 break;
920 case ATOMIC_BEGIN:
921 break;
922 case ATOMIC_END:
923 break;
924 case SET_RETURN_VALUE:
926 vm,
927 _code.get_statement() == ID_return,
928 "SET_RETURN_VALUE instruction should contain a return statement",
929 source_location());
930 break;
931 case ASSIGN:
933 vm,
934 _code.get_statement() == ID_assign,
935 "assign instruction should contain an assign statement");
937 vm, targets.empty(), "assign instruction should not have a target");
938 break;
939 case DECL:
941 vm,
942 _code.get_statement() == ID_decl,
943 "declaration instructions should contain a declaration statement",
944 source_location());
946 vm,
947 !ns.lookup(decl_symbol().get_identifier(), table_symbol),
948 "declared symbols should be known",
949 id2string(decl_symbol().get_identifier()),
950 source_location());
951 break;
952 case DEAD:
954 vm,
955 _code.get_statement() == ID_dead,
956 "dead instructions should contain a dead statement",
957 source_location());
959 vm,
960 !ns.lookup(dead_symbol().get_identifier(), table_symbol),
961 "removed symbols should be known",
962 id2string(dead_symbol().get_identifier()),
963 source_location());
964 break;
965 case FUNCTION_CALL:
967 vm,
968 _code.get_statement() == ID_function_call,
969 "function call instruction should contain a call statement",
970 source_location());
971
972 expr_symbol_finder(_code);
973 std::for_each(_code.depth_begin(), _code.depth_end(), type_finder);
974 break;
975 case THROW:
976 break;
977 case CATCH:
978 break;
979 case INCOMPLETE_GOTO:
980 break;
981 }
982}
983
985 std::function<std::optional<exprt>(exprt)> f)
986{
987 switch(_type)
988 {
989 case OTHER:
990 if(get_other().get_statement() == ID_expression)
991 {
992 auto new_expression = f(to_code_expression(get_other()).expression());
993 if(new_expression.has_value())
994 {
995 auto new_other = to_code_expression(get_other());
996 new_other.expression() = *new_expression;
997 set_other(new_other);
998 }
999 }
1000 break;
1001
1002 case SET_RETURN_VALUE:
1003 {
1004 auto new_return_value = f(return_value());
1005 if(new_return_value.has_value())
1006 return_value() = *new_return_value;
1007 }
1008 break;
1009
1010 case ASSIGN:
1011 {
1012 auto new_assign_lhs = f(assign_lhs());
1013 auto new_assign_rhs = f(assign_rhs());
1014 if(new_assign_lhs.has_value())
1015 assign_lhs_nonconst() = new_assign_lhs.value();
1016 if(new_assign_rhs.has_value())
1017 assign_rhs_nonconst() = new_assign_rhs.value();
1018 }
1019 break;
1020
1021 case DECL:
1022 {
1023 auto new_symbol = f(decl_symbol());
1024 if(new_symbol.has_value())
1025 decl_symbol() = to_symbol_expr(*new_symbol);
1026 }
1027 break;
1028
1029 case DEAD:
1030 {
1031 auto new_symbol = f(dead_symbol());
1032 if(new_symbol.has_value())
1033 dead_symbol() = to_symbol_expr(*new_symbol);
1034 }
1035 break;
1036
1037 case FUNCTION_CALL:
1038 {
1039 auto new_lhs = f(as_const(*this).call_lhs());
1040 if(new_lhs.has_value())
1041 call_lhs() = *new_lhs;
1042
1043 auto new_call_function = f(as_const(*this).call_function());
1044 if(new_call_function.has_value())
1045 call_function() = *new_call_function;
1046
1047 exprt::operandst new_arguments = as_const(*this).call_arguments();
1048 bool argument_changed = false;
1049
1050 for(auto &a : new_arguments)
1051 {
1052 auto new_a = f(a);
1053 if(new_a.has_value())
1054 {
1055 a = *new_a;
1056 argument_changed = true;
1057 }
1058 }
1059
1061 call_arguments() = std::move(new_arguments);
1062 }
1063 break;
1064
1065 case GOTO:
1066 case ASSUME:
1067 case ASSERT:
1068 case SKIP:
1069 case START_THREAD:
1070 case END_THREAD:
1071 case LOCATION:
1072 case END_FUNCTION:
1073 case ATOMIC_BEGIN:
1074 case ATOMIC_END:
1075 case THROW:
1076 case CATCH:
1077 case INCOMPLETE_GOTO:
1079 if(has_condition())
1080 {
1081 auto new_condition = f(condition());
1082 if(new_condition.has_value())
1083 condition_nonconst() = new_condition.value();
1084 }
1085 }
1086}
1087
1089 std::function<void(const exprt &)> f) const
1090{
1091 switch(_type)
1092 {
1093 case OTHER:
1094 if(get_other().get_statement() == ID_expression)
1095 f(to_code_expression(get_other()).expression());
1096 break;
1097
1098 case SET_RETURN_VALUE:
1099 f(return_value());
1100 break;
1101
1102 case ASSIGN:
1103 f(assign_lhs());
1104 f(assign_rhs());
1105 break;
1106
1107 case DECL:
1108 f(decl_symbol());
1109 break;
1110
1111 case DEAD:
1112 f(dead_symbol());
1113 break;
1114
1115 case FUNCTION_CALL:
1116 f(call_lhs());
1117 for(auto &a : call_arguments())
1118 f(a);
1119 break;
1120
1121 case GOTO:
1122 case ASSUME:
1123 case ASSERT:
1124 case SKIP:
1125 case START_THREAD:
1126 case END_THREAD:
1127 case LOCATION:
1128 case END_FUNCTION:
1129 case ATOMIC_BEGIN:
1130 case ATOMIC_END:
1131 case THROW:
1132 case CATCH:
1133 case INCOMPLETE_GOTO:
1135 if(has_condition())
1136 f(condition());
1137 }
1138}
1139
1140bool goto_programt::equals(const goto_programt &other) const
1141{
1142 if(instructions.size() != other.instructions.size())
1143 return false;
1144
1146 for(const auto &ins : instructions)
1147 {
1148 if(!ins.equals(*other_it))
1149 return false;
1150
1151 // the number of targets is the same as instructiont::equals returned "true"
1152 auto other_target_it = other_it->targets.begin();
1153 for(const auto &t : ins.targets)
1154 {
1155 if(
1156 t->location_number - ins.location_number !=
1157 (*other_target_it)->location_number - other_it->location_number)
1158 {
1159 return false;
1160 }
1161
1163 }
1164
1165 ++other_it;
1166 }
1167
1168 return true;
1169}
1170
1172std::ostream &operator<<(std::ostream &out, goto_program_instruction_typet t)
1173{
1174 switch(t)
1175 {
1177 out << "NO_INSTRUCTION_TYPE";
1178 break;
1179 case GOTO:
1180 out << "GOTO";
1181 break;
1182 case ASSUME:
1183 out << "ASSUME";
1184 break;
1185 case ASSERT:
1186 out << "ASSERT";
1187 break;
1188 case OTHER:
1189 out << "OTHER";
1190 break;
1191 case DECL:
1192 out << "DECL";
1193 break;
1194 case DEAD:
1195 out << "DEAD";
1196 break;
1197 case SKIP:
1198 out << "SKIP";
1199 break;
1200 case START_THREAD:
1201 out << "START_THREAD";
1202 break;
1203 case END_THREAD:
1204 out << "END_THREAD";
1205 break;
1206 case LOCATION:
1207 out << "LOCATION";
1208 break;
1209 case END_FUNCTION:
1210 out << "END_FUNCTION";
1211 break;
1212 case ATOMIC_BEGIN:
1213 out << "ATOMIC_BEGIN";
1214 break;
1215 case ATOMIC_END:
1216 out << "ATOMIC_END";
1217 break;
1218 case SET_RETURN_VALUE:
1219 out << "SET_RETURN_VALUE";
1220 break;
1221 case ASSIGN:
1222 out << "ASSIGN";
1223 break;
1224 case FUNCTION_CALL:
1225 out << "FUNCTION_CALL";
1226 break;
1227 case THROW:
1228 out << "THROW";
1229 break;
1230 case CATCH:
1231 out << "CATCH";
1232 break;
1233 case INCOMPLETE_GOTO:
1234 out << "INCOMPLETE_GOTO";
1235 break;
1236 }
1237
1238 return out;
1239}
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition as_const.h:14
static exprt guard(const exprt::operandst &guards, exprt cond)
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
codet representation of a goto statement.
Definition std_code.h:841
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
operandst & operands()
Definition expr.h:94
This class represents an instruction in the GOTO intermediate representation.
const symbol_exprt & dead_symbol() const
Get the symbol for DEAD.
const exprt & call_lhs() const
Get the lhs of a FUNCTION_CALL (may be nil)
const goto_instruction_codet & get_other() const
Get the statement for OTHER.
unsigned target_number
A number to identify branch targets.
bool is_target() const
Is this node a branch target?
const exprt & return_value() const
Get the return value of a SET_RETURN_VALUE instruction.
const goto_instruction_codet & code() const
Get the code represented by this instruction.
goto_instruction_codet _code
Do not read or modify directly – use code() and code_nonconst() instead.
void apply(std::function< void(const exprt &)>) const
Apply given function to all expressions.
const symbol_exprt & decl_symbol() const
Get the declared symbol for DECL.
targetst targets
The list of successor instructions.
goto_program_instruction_typet _type
bool equals(const instructiont &other) const
Syntactic equality: two instructiont are equal if they have the same type, code, guard,...
void transform(std::function< std::optional< exprt >(exprt)>)
Apply given transformer to all expressions; no return value means no change needed.
const exprt::operandst & call_arguments() const
Get the arguments of a FUNCTION_CALL.
unsigned location_number
A globally unique number to identify a program location.
const exprt & assign_lhs() const
Get the lhs of the assignment for ASSIGN.
static const unsigned nil_target
Uniquely identify an invalid target or location.
const exprt & assign_rhs() const
Get the rhs of the assignment for ASSIGN.
const exprt & call_function() const
Get the function that is called for FUNCTION_CALL.
std::ostream & output(std::ostream &) const
Output this instruction to the given stream.
exprt guard
Guard for gotos, assume, assert Use condition() method to access.
const exprt & condition() const
Get the condition of gotos, assume, assert.
const source_locationt & source_location() const
const_targett get_target() const
Returns the first (and only) successor for the usual case of a single target.
goto_program_instruction_typet type() const
What kind of instruction?
void validate(const namespacet &ns, const validation_modet vm) const
Check that the instruction is well-formed.
A generic container class for the GOTO intermediate representation of one function.
instructionst instructions
The list of instructions in the goto program.
void copy_from(const goto_programt &src)
Copy a full goto program, preserving targets.
void clear()
Clear the goto program.
void update()
Update all indices.
std::ostream & output(std::ostream &out) const
Output goto-program to given stream.
bool has_assertion() const
Does the goto program have an assertion?
instructionst::const_iterator const_targett
targett add_instruction()
Adds an instruction at the end.
void compute_incoming_edges()
Compute for each instruction the set of instructions it is a successor of.
std::set< irep_idt > decl_identifierst
void get_decl_identifiers(decl_identifierst &decl_identifiers) const
get the variables in decl statements
std::list< Target > get_successors(Target target) const
Get control-flow successors of a given instruction.
void compute_location_numbers()
Compute location numbers.
void compute_target_numbers()
Compute the target numbers.
bool equals(const goto_programt &other) const
Syntactic equality: two goto_programt are equal if, and only if, they have the same number of instruc...
static instructiont make_incomplete_goto(const exprt &_cond, const source_locationt &l=source_locationt::nil())
void compute_loop_numbers()
Compute loop numbers.
const irep_idt & id() const
Definition irep.h:388
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The NIL expression.
Definition std_expr.h:3208
Symbol table entry.
Definition symbol.h:28
The Boolean constant true.
Definition std_expr.h:3190
Forward depth-first search iterators These iterators' copy operations are expensive,...
void find_type_and_expr_symbols(const exprt &src, find_symbols_sett &dest, const std::vector< irep_idt > &subs_to_find)
Find identifiers with id ID_symbol of the sub expressions and the subs with ID in subs_to_find consid...
std::unordered_set< irep_idt > find_symbols_sett
static format_containert< T > format(const T &o)
Definition format.h:37
void parse_lhs_read(const exprt &src, std::list< exprt > &dest)
Concrete Goto Program.
std::list< exprt > expressions_read(const goto_programt::instructiont &)
std::list< exprt > objects_written(const goto_programt::instructiont &)
std::ostream & operator<<(std::ostream &, goto_program_instruction_typet)
Outputs a string representation of a goto_program_instruction_typet
goto_program_instruction_typet
The type of an instruction in a GOTO program.
@ FUNCTION_CALL
@ ATOMIC_END
@ DEAD
@ LOCATION
@ END_FUNCTION
@ ASSIGN
@ ASSERT
@ SET_RETURN_VALUE
@ ATOMIC_BEGIN
@ CATCH
@ END_THREAD
@ SKIP
@ NO_INSTRUCTION_TYPE
@ START_THREAD
@ THROW
@ DECL
@ OTHER
@ GOTO
@ INCOMPLETE_GOTO
@ ASSUME
std::string as_string(const namespacet &ns, const irep_idt &function, const goto_programt::instructiont &)
std::list< exprt > expressions_written(const goto_programt::instructiont &)
std::list< exprt > objects_read(const goto_programt::instructiont &)
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
API to expression classes for Pointers.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
static std::string comment(const rw_set_baset::entryt &entry, bool write)
#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
static code_landingpadt & to_code_landingpad(codet &code)
Definition std_code.h:1972
code_expressiont & to_code_expression(codet &code)
Definition std_code.h:1428
API to expression classes.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
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
Symbol table entry.
#define DATA_CHECK_WITH_DIAGNOSTICS(vm, condition, message,...)
Definition validate.h:37
#define DATA_CHECK(vm, condition, message)
This macro takes a condition which denotes a well-formedness criterion on goto programs,...
Definition validate.h:22
void validate_full_code(const codet &code, const namespacet &ns, const validation_modet vm)
Check that the given code statement is well-formed (full check, including checks of all subexpression...
void validate_full_expr(const exprt &expr, const namespacet &ns, const validation_modet vm)
Check that the given expression is well-formed (full check, including checks of all subexpressions an...
validation_modet