cprover
Loading...
Searching...
No Matches
builtin_functions.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_convert_class.h"
13
14#include <util/arith_tools.h>
15#include <util/c_types.h>
16#include <util/cprover_prefix.h>
18#include <util/expr_util.h>
19#include <util/fresh_symbol.h>
22#include <util/pointer_expr.h>
23#include <util/rational.h>
24#include <util/rational_tools.h>
25#include <util/simplify_expr.h>
26#include <util/symbol.h>
27
29
30#include "destructor.h"
31#include "format_strings.h"
32
34 const exprt &lhs,
35 const symbol_exprt &function,
36 const exprt::operandst &arguments,
37 goto_programt &dest)
38{
39 const irep_idt &identifier = function.identifier();
40
41 // make it a side effect if there is an LHS
42 if(arguments.size() != 2)
43 {
45 error() << "'" << identifier << "' expected to have two arguments" << eom;
46 throw 0;
47 }
48
49 if(lhs.is_nil())
50 {
52 error() << "'" << identifier << "' expected to have LHS" << eom;
53 throw 0;
54 }
55
56 auto rhs =
57 side_effect_exprt("prob_uniform", lhs.type(), function.source_location());
58
59 if(lhs.type().id() != ID_unsignedbv && lhs.type().id() != ID_signedbv)
60 {
62 error() << "'" << identifier << "' expected other type" << eom;
63 throw 0;
64 }
65
66 if(
67 arguments[0].type().id() != lhs.type().id() ||
68 arguments[1].type().id() != lhs.type().id())
69 {
71 error() << "'" << identifier
72 << "' expected operands to be of same type as LHS" << eom;
73 throw 0;
74 }
75
76 if(!arguments[0].is_constant() || !arguments[1].is_constant())
77 {
79 error() << "'" << identifier
80 << "' expected operands to be constant literals" << eom;
81 throw 0;
82 }
83
84 mp_integer lb, ub;
85
86 if(
87 to_integer(to_constant_expr(arguments[0]), lb) ||
88 to_integer(to_constant_expr(arguments[1]), ub))
89 {
91 error() << "error converting operands" << eom;
92 throw 0;
93 }
94
95 if(lb > ub)
96 {
98 error() << "expected lower bound to be smaller or equal to the "
99 << "upper bound" << eom;
100 throw 0;
101 }
102
103 rhs.add_to_operands(exprt{arguments[0]}, exprt{arguments[1]});
104
105 code_assignt assignment(lhs, rhs);
106 assignment.add_source_location() = function.source_location();
107 copy(assignment, ASSIGN, dest);
108}
109
111 const exprt &lhs,
112 const symbol_exprt &function,
113 const exprt::operandst &arguments,
114 goto_programt &dest)
115{
116 const irep_idt &identifier = function.identifier();
117
118 // make it a side effect if there is an LHS
119 if(arguments.size() != 2)
120 {
122 error() << "'" << identifier << "' expected to have two arguments" << eom;
123 throw 0;
124 }
125
126 if(lhs.is_nil())
127 {
129 error() << "'" << identifier << "' expected to have LHS" << eom;
130 throw 0;
131 }
132
133 side_effect_exprt rhs("prob_coin", lhs.type(), function.source_location());
134
135 if(lhs.type() != bool_typet())
136 {
138 error() << "'" << identifier << "' expected bool" << eom;
139 throw 0;
140 }
141
142 if(arguments[0].type().id() != ID_unsignedbv || !arguments[0].is_constant())
143 {
145 error() << "'" << identifier << "' expected first operand to be "
146 << "a constant literal of type unsigned long" << eom;
147 throw 0;
148 }
149
150 if(arguments[1].type().id() != ID_unsignedbv || !arguments[1].is_constant())
151 {
153 error() << "'" << identifier << "' expected second operand to be "
154 << "a constant literal of type unsigned long" << eom;
155 throw 0;
156 }
157
158 mp_integer num, den;
159
160 if(
161 to_integer(to_constant_expr(arguments[0]), num) ||
162 to_integer(to_constant_expr(arguments[1]), den))
163 {
165 error() << "error converting operands" << eom;
166 throw 0;
167 }
168
169 if(num - den > mp_integer(0))
170 {
172 error() << "probability has to be smaller than 1" << eom;
173 throw 0;
174 }
175
176 if(den == mp_integer(0))
177 {
179 error() << "denominator may not be zero" << eom;
180 throw 0;
181 }
182
183 rationalt numerator(num), denominator(den);
184 rationalt prob = numerator / denominator;
185
187
188 code_assignt assignment(lhs, rhs);
189 assignment.add_source_location() = function.source_location();
190 copy(assignment, ASSIGN, dest);
191}
192
194 const exprt &lhs,
195 const symbol_exprt &function,
196 const exprt::operandst &arguments,
197 goto_programt &dest)
198{
199 const irep_idt &f_id = function.identifier();
200
201 PRECONDITION(f_id == CPROVER_PREFIX "printf");
202
203 codet printf_code(ID_printf, arguments, function.source_location());
204 copy(printf_code, OTHER, dest);
205}
206
208 const exprt &lhs,
209 const symbol_exprt &function,
210 const exprt::operandst &arguments,
211 goto_programt &dest)
212{
213 const irep_idt &f_id = function.identifier();
214
215 if(f_id == CPROVER_PREFIX "scanf")
216 {
217 if(arguments.empty())
218 {
220 error() << "scanf takes at least one argument" << eom;
221 throw 0;
222 }
223
224 irep_idt format_string;
225
226 if(!get_string_constant(arguments[0], format_string))
227 {
228 // use our model
229 format_token_listt token_list =
230 parse_format_string(id2string(format_string));
231
232 std::size_t argument_number = 1;
233
234 for(const auto &t : token_list)
235 {
236 const auto type = get_type(t);
237
238 if(type.has_value())
239 {
240 if(argument_number < arguments.size())
241 {
242 const typecast_exprt ptr(
243 arguments[argument_number], pointer_type(*type));
244 argument_number++;
245
246 if(type->id() == ID_array)
247 {
248#if 0
249 // A string. We first need a nondeterministic size.
251 to_array_type(*type).size()=size;
252
253 const symbolt &tmp_symbol=
255 *type, "scanf_string", dest, function.source_location());
256
257 const address_of_exprt rhs(
259 tmp_symbol.symbol_expr(),
261
262 // now use array copy
263 codet array_copy_statement;
264 array_copy_statement.set_statement(ID_array_copy);
265 array_copy_statement.operands().resize(2);
266 array_copy_statement.op0()=ptr;
267\ array_copy_statement.op1()=rhs;
268 array_copy_statement.add_source_location()=
269 function.source_location();
270
271 copy(array_copy_statement, OTHER, dest);
272#else
273 const index_exprt new_lhs(
275 const side_effect_expr_nondett rhs(
277 function.source_location());
278 code_assignt assign(new_lhs, rhs);
279 assign.add_source_location() = function.source_location();
280 copy(assign, ASSIGN, dest);
281#endif
282 }
283 else
284 {
285 // make it nondet for now
286 const dereference_exprt new_lhs{ptr};
287 const side_effect_expr_nondett rhs(
288 *type, function.source_location());
289 code_assignt assign(new_lhs, rhs);
290 assign.add_source_location() = function.source_location();
291 copy(assign, ASSIGN, dest);
292 }
293 }
294 }
295 }
296 }
297 else
298 {
299 // we'll just do nothing
300 code_function_callt function_call(lhs, function, arguments);
301 function_call.add_source_location() = function.source_location();
302
303 copy(function_call, FUNCTION_CALL, dest);
304 }
305 }
306 else
308}
309
311 const exprt &function,
312 const exprt::operandst &arguments,
313 goto_programt &dest)
314{
315 if(arguments.size() < 2)
316 {
318 error() << "input takes at least two arguments" << eom;
319 throw 0;
320 }
321
322 copy(code_inputt{arguments, function.source_location()}, OTHER, dest);
323}
324
326 const exprt &function,
327 const exprt::operandst &arguments,
328 goto_programt &dest)
329{
330 if(arguments.size() < 2)
331 {
333 error() << "output takes at least two arguments" << eom;
334 throw 0;
335 }
336
337 copy(code_outputt{arguments, function.source_location()}, OTHER, dest);
338}
339
341 const exprt &lhs,
342 const symbol_exprt &function,
343 const exprt::operandst &arguments,
344 goto_programt &dest)
345{
346 if(lhs.is_not_nil())
347 {
349 error() << "atomic_begin does not expect an LHS" << eom;
350 throw 0;
351 }
352
353 if(!arguments.empty())
354 {
356 error() << "atomic_begin takes no arguments" << eom;
357 throw 0;
358 }
359
361}
362
364 const exprt &lhs,
365 const symbol_exprt &function,
366 const exprt::operandst &arguments,
367 goto_programt &dest)
368{
369 if(lhs.is_not_nil())
370 {
372 error() << "atomic_end does not expect an LHS" << eom;
373 throw 0;
374 }
375
376 if(!arguments.empty())
377 {
379 error() << "atomic_end takes no arguments" << eom;
380 throw 0;
381 }
382
384}
385
387 const exprt &lhs,
388 const side_effect_exprt &rhs,
389 goto_programt &dest)
390{
391 if(lhs.is_nil())
392 {
394 error() << "do_cpp_new without lhs is yet to be implemented" << eom;
395 throw 0;
396 }
397
398 // build size expression
399 exprt object_size = static_cast<const exprt &>(rhs.find(ID_sizeof));
400
401 bool new_array = rhs.get(ID_statement) == ID_cpp_new_array;
402
403 exprt count;
404 clean_expr_resultt side_effects;
405
406 if(new_array)
407 {
409 static_cast<const exprt &>(rhs.find(ID_size)), object_size.type());
410
411 // might have side-effect
412 side_effects.add(clean_expr(count, ID_cpp));
413 dest.destructive_append(side_effects.side_effects);
414 }
415
416 exprt tmp_symbol_expr;
417
418 // is this a placement new?
419 if(rhs.operands().empty()) // no, "regular" one
420 {
421 // call __new or __new_array
422 exprt new_symbol =
423 ns.lookup(new_array ? "__new_array" : "__new").symbol_expr();
424
425 const code_typet &code_type = to_code_type(new_symbol.type());
426
427 const typet &return_type = code_type.return_type();
428
430 code_type.parameters().size() == 1 || code_type.parameters().size() == 2,
431 "new has one or two parameters");
432
433 const symbolt &tmp_symbol =
434 new_tmp_symbol(return_type, "new", dest, rhs.source_location(), ID_cpp);
435
436 tmp_symbol_expr = tmp_symbol.symbol_expr();
437
438 code_function_callt new_call(new_symbol);
439 if(new_array)
440 new_call.arguments().push_back(count);
441 new_call.arguments().push_back(object_size);
442 new_call.set(
443 ID_C_cxx_alloc_type, to_type_with_subtype(lhs.type()).subtype());
444 new_call.lhs() = tmp_symbol_expr;
445 new_call.add_source_location() = rhs.source_location();
446
447 convert(new_call, dest, ID_cpp);
448 }
449 else if(rhs.operands().size() == 1)
450 {
451 // call __placement_new
452 exprt new_symbol =
453 ns.lookup(new_array ? "__placement_new_array" : "__placement_new")
454 .symbol_expr();
455
456 const code_typet &code_type = to_code_type(new_symbol.type());
457
458 const typet &return_type = code_type.return_type();
459
461 code_type.parameters().size() == 2 || code_type.parameters().size() == 3,
462 "placement new has two or three parameters");
463
464 const symbolt &tmp_symbol =
465 new_tmp_symbol(return_type, "new", dest, rhs.source_location(), ID_cpp);
466
467 tmp_symbol_expr = tmp_symbol.symbol_expr();
468
469 code_function_callt new_call(new_symbol);
470 if(new_array)
471 new_call.arguments().push_back(count);
472 new_call.arguments().push_back(object_size);
473 new_call.arguments().push_back(to_unary_expr(rhs).op()); // memory location
474 new_call.set(
475 ID_C_cxx_alloc_type, to_type_with_subtype(lhs.type()).subtype());
476 new_call.lhs() = tmp_symbol_expr;
477 new_call.add_source_location() = rhs.source_location();
478
479 for(std::size_t i = 0; i < code_type.parameters().size(); i++)
480 {
482 new_call.arguments()[i], code_type.parameters()[i].type());
483 }
484
485 convert(new_call, dest, ID_cpp);
486 }
487 else
488 {
490 error() << "cpp_new expected to have 0 or 1 operands" << eom;
491 throw 0;
492 }
493
495 lhs,
496 typecast_exprt(tmp_symbol_expr, lhs.type()),
497 rhs.find_source_location()));
498
499 side_effects.add_temporary(to_symbol_expr(tmp_symbol_expr).identifier());
500 destruct_locals(side_effects.temporaries, dest, ns);
501
502 // grab initializer
503 goto_programt tmp_initializer;
504 cpp_new_initializer(lhs, rhs, tmp_initializer);
505
506 dest.destructive_append(tmp_initializer);
507}
508
511 const exprt &lhs,
512 const side_effect_exprt &rhs,
513 goto_programt &dest)
514{
515 exprt initializer = static_cast<const exprt &>(rhs.find(ID_initializer));
516
517 if(initializer.is_not_nil())
518 {
519 if(rhs.get_statement() == "cpp_new[]")
520 {
521 // build loop
522 }
523 else if(rhs.get_statement() == ID_cpp_new)
524 {
525 // just one object
526 const dereference_exprt deref_lhs(
527 lhs, to_pointer_type(rhs.type()).base_type());
528
529 replace_new_object(deref_lhs, initializer);
530 convert(to_code(initializer), dest, ID_cpp);
531 }
532 else
534 }
535}
536
538{
539 if(src.id() == ID_typecast)
540 return get_array_argument(to_typecast_expr(src).op());
541
542 if(src.id() != ID_address_of)
543 {
545 error() << "expected array-pointer as argument" << eom;
546 throw 0;
547 }
548
549 const auto &address_of_expr = to_address_of_expr(src);
550
551 if(address_of_expr.object().id() != ID_index)
552 {
554 error() << "expected array-element as argument" << eom;
555 throw 0;
556 }
557
558 const auto &index_expr = to_index_expr(address_of_expr.object());
559
560 if(index_expr.array().type().id() != ID_array)
561 {
563 error() << "expected array as argument" << eom;
564 throw 0;
565 }
566
567 return index_expr.array();
568}
569
571 const irep_idt &id,
572 const exprt &lhs,
573 const symbol_exprt &function,
574 const exprt::operandst &arguments,
575 goto_programt &dest)
576{
577 if(arguments.size() != 2)
578 {
580 error() << id << " expects two arguments" << eom;
581 throw 0;
582 }
583
584 codet array_op_statement(id);
585 array_op_statement.operands() = arguments;
586 array_op_statement.add_source_location() = function.source_location();
587
588 // lhs is only used with array_equal, in all other cases it should be nil (as
589 // they are of type void)
590 if(id == ID_array_equal)
591 array_op_statement.copy_to_operands(lhs);
592
593 copy(array_op_statement, OTHER, dest);
594}
595
596static exprt make_va_list(const exprt &expr, const namespacet &ns)
597{
598 if(
599 auto struct_tag_type = type_try_dynamic_cast<struct_tag_typet>(expr.type()))
600 {
601 // aarch64 ABI mandates that va_list has struct type with member names as
602 // specified
603 const auto &components = ns.follow_tag(*struct_tag_type).components();
605 components.size() == 5,
606 "va_list struct type expected to have 5 components");
607 return member_exprt{expr, components.front()};
608 }
609
610 exprt result = skip_typecast(expr);
611
612 // if it's an address of an lvalue, we take that
613 if(result.id() == ID_address_of)
614 {
615 const auto &address_of_expr = to_address_of_expr(result);
616 if(is_assignable(address_of_expr.object()))
617 result = address_of_expr.object();
618 }
619
620 while(result.type().id() == ID_array &&
621 to_array_type(result.type()).size() == 1)
622 {
623 result = index_exprt{result, from_integer(0, c_index_type())};
624 }
625
626 return result;
627}
628
630 const exprt &lhs,
631 const symbol_exprt &function,
632 const exprt::operandst &arguments,
633 goto_programt &dest,
634 const irep_idt &mode)
635{
636 irep_idt identifier = CPROVER_PREFIX "havoc_slice";
637
638 // We disable checks on the generated instructions
639 // because we add our own rw_ok assertion that takes size into account
640 auto source_location = function.find_source_location();
641 source_location.add_pragma("disable:pointer-check");
642 source_location.add_pragma("disable:pointer-overflow-check");
643 source_location.add_pragma("disable:pointer-primitive-check");
644
645 // check # arguments
646 if(arguments.size() != 2)
647 {
648 error().source_location = source_location;
649 error() << "'" << identifier << "' expected to have two arguments" << eom;
650 throw 0;
651 }
652
653 // check argument types
654 if(arguments[0].type().id() != ID_pointer)
655 {
656 error().source_location = source_location;
657 error() << "'" << identifier
658 << "' first argument expected to have `void *` type" << eom;
659 throw 0;
660 }
661
662 if(arguments[1].type().id() != ID_unsignedbv)
663 {
664 error().source_location = source_location;
665 error() << "'" << identifier
666 << "' second argument expected to have `size_t` type" << eom;
667 throw 0;
668 }
669
670 // check nil lhs
671 if(lhs.is_not_nil())
672 {
673 error().source_location = source_location;
674 error() << "'" << identifier << "' not expected to have a LHS" << eom;
675 throw 0;
676 }
677
678 // insert instructions
679 // assert(rw_ok(argument[0], argument[1]));
680 // unsigned char nondet_contents[argument[1]];
681 // __CPROVER_array_replace(p, nondet_contents);
682 //
683 // Note that we use "unsigned char" explicitly here to force stable
684 // output on platforms where plain "char" is implementation-defined and signed
685 // by default
686
687 r_or_w_ok_exprt ok_expr(ID_w_ok, arguments[0], arguments[1]);
688 ok_expr.add_source_location() = source_location;
689 source_locationt annotated_location = source_location;
690 annotated_location.set("user-provided", false);
691 annotated_location.set_property_class(ID_assertion);
692 annotated_location.set_comment(
693 "assertion havoc_slice " + from_expr(ns, identifier, ok_expr));
694 dest.add(goto_programt::make_assertion(ok_expr, annotated_location));
695
696 const array_typet array_type(
697 unsigned_char_type(), simplify_expr(arguments[1], ns));
698
699 const symbolt &nondet_contents =
700 new_tmp_symbol(array_type, "nondet_contents", dest, source_location, mode);
701 const exprt &nondet_contents_expr = address_of_exprt{index_exprt{
702 nondet_contents.symbol_expr(), from_integer(0, c_index_type())}};
703
704 const exprt &arg0 =
707 nondet_contents_expr, pointer_type(empty_typet{}));
708
709 codet array_replace(ID_array_replace, {arg0, arg1}, source_location);
710 dest.add(goto_programt::make_other(array_replace, source_location));
711
712 destruct_locals({nondet_contents.name}, dest, ns);
713}
714
718 const exprt &lhs,
719 const symbol_exprt &function,
720 const exprt::operandst &arguments,
721 goto_programt &dest,
722 const irep_idt &mode)
723{
724 const source_locationt &source_location = function.source_location();
725 const auto alloca_type = to_code_type(function.type());
726
727 if(alloca_type.return_type() != pointer_type(void_type()))
728 {
729 error().source_location = source_location;
730 error() << "'alloca' function called, but 'alloca' has not been declared "
731 << "with expected 'void *' return type." << eom;
732 throw 0;
733 }
734 if(
735 alloca_type.parameters().size() != 1 ||
736 alloca_type.parameters()[0].type() != size_type())
737 {
738 error().source_location = source_location;
739 error() << "'alloca' function called, but 'alloca' has not been declared "
740 << "with expected single 'size_t' parameter." << eom;
741 throw 0;
742 }
743
744 exprt new_lhs = lhs;
745
746 // make sure we have a left-hand side to track the allocation even when the
747 // original program did not
748 if(lhs.is_nil())
749 {
750 new_lhs =
752 alloca_type.return_type(), "alloca", dest, source_location, mode)
753 .symbol_expr();
754 }
755
756 // do the actual function call
757 code_function_callt function_call(new_lhs, function, arguments);
758 function_call.add_source_location() = source_location;
759 copy(function_call, FUNCTION_CALL, dest);
760
761 // Don't add instrumentation when we're in alloca (which might in turn call
762 // __builtin_alloca) -- the instrumentation will be done for the call of
763 // alloca. Also, we can only add instrumentation when we're in a function
764 // context.
765 if(
766 function.source_location().get_function() == "alloca" || !targets.prefix ||
767 !targets.suffix)
768 {
769 return;
770 }
771
772 // create a symbol to eventually (and non-deterministically) mark the
773 // allocation as dead; this symbol has function scope and is initialised to
774 // NULL
775 symbol_exprt this_alloca_ptr =
777 alloca_type.return_type(),
779 "tmp_alloca",
780 source_location,
781 mode,
783 .symbol_expr();
784 goto_programt decl_prg;
785 decl_prg.add(goto_programt::make_decl(this_alloca_ptr, source_location));
787 this_alloca_ptr,
788 null_pointer_exprt{to_pointer_type(this_alloca_ptr.type())},
789 source_location));
790 targets.prefix->destructive_insert(
791 targets.prefix->instructions.begin(), decl_prg);
792
793 // non-deterministically update this_alloca_ptr
794 if_exprt rhs{
795 side_effect_expr_nondett{bool_typet(), source_location},
796 new_lhs,
797 this_alloca_ptr};
799 this_alloca_ptr, std::move(rhs), source_location));
800
801 if(lhs.is_nil())
802 destruct_locals({to_symbol_expr(new_lhs).identifier()}, dest, ns);
803
804 // mark pointer to alloca result as dead, unless the alloca result (in
805 // this_alloca_ptr) is still NULL
806 symbol_exprt dead_object_sym =
807 ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
808 exprt alloca_result =
809 typecast_exprt::conditional_cast(this_alloca_ptr, dead_object_sym.type());
810 if_exprt not_null{
812 this_alloca_ptr,
813 null_pointer_exprt{to_pointer_type(this_alloca_ptr.type())}},
814 dead_object_sym,
815 std::move(alloca_result)};
816 auto assign = goto_programt::make_assignment(
817 std::move(dead_object_sym), std::move(not_null), source_location);
818 targets.suffix->insert_before_swap(
819 targets.suffix->instructions.begin(), assign);
820 targets.suffix->insert_after(
821 targets.suffix->instructions.begin(),
822 goto_programt::make_dead(this_alloca_ptr, source_location));
823}
824
827 const exprt &lhs,
828 const symbol_exprt &function,
829 const exprt::operandst &arguments,
830 goto_programt &dest,
831 const irep_idt &mode)
832{
833 if(function.get_bool(ID_C_invalid_object))
834 return; // ignore
835
836 // lookup symbol
837 const irep_idt &identifier = function.identifier();
838
839 const symbolt *symbol;
840 if(ns.lookup(identifier, symbol))
841 {
843 error() << "function '" << identifier << "' not found" << eom;
844 throw 0;
845 }
846
847 if(symbol->type.id() != ID_code)
848 {
850 error() << "function '" << identifier << "' type mismatch: expected code"
851 << eom;
852 throw 0;
853 }
854
855 // User-provided function definitions always take precedence over built-ins.
856 // Front-ends do not (yet) consistently set ID_C_incomplete, thus also test
857 // whether the symbol actually has some non-nil value (which might be
858 // "compiled").
859 if(!symbol->type.get_bool(ID_C_incomplete) && symbol->value.is_not_nil())
860 {
862
863 // use symbol->symbol_expr() to ensure we use the type from the symbol table
864 code_function_callt function_call(
865 lhs, symbol->symbol_expr().with_source_location(function), arguments);
866 function_call.add_source_location() = function.source_location();
867
868 // remove void-typed assignments, which may have been created when the
869 // front-end was unable to detect them in type checking for a lack of
870 // available declarations
871 if(
872 lhs.is_not_nil() &&
873 to_code_type(symbol->type).return_type().id() == ID_empty)
874 {
875 function_call.lhs().make_nil();
876 }
877
878 copy(function_call, FUNCTION_CALL, dest);
879
880 return;
881 }
882
883 if(identifier == CPROVER_PREFIX "havoc_slice")
884 {
885 do_havoc_slice(lhs, function, arguments, dest, mode);
886 }
887 else if(
888 identifier == CPROVER_PREFIX "assume" || identifier == "__VERIFIER_assume")
889 {
890 if(arguments.size() != 1)
891 {
893 error() << "'" << identifier << "' expected to have one argument" << eom;
894 throw 0;
895 }
896
897 // let's double-check the type of the argument
898 source_locationt annotated_location = function.source_location();
899 annotated_location.set("user-provided", true);
901 typecast_exprt::conditional_cast(arguments.front(), bool_typet()),
902 annotated_location));
903
904 if(lhs.is_not_nil())
905 {
907 error() << identifier << " expected not to have LHS" << eom;
908 throw 0;
909 }
910 }
911 else if(identifier == "__VERIFIER_error")
912 {
913 if(!arguments.empty())
914 {
916 error() << "'" << identifier << "' expected to have no arguments" << eom;
917 throw 0;
918 }
919
920 source_locationt annotated_location = function.source_location();
921 annotated_location.set("user-provided", true);
922 annotated_location.set_property_class(ID_assertion);
923 dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
924
925 if(lhs.is_not_nil())
926 {
928 error() << identifier << " expected not to have LHS" << eom;
929 throw 0;
930 }
931
932 // __VERIFIER_error has abort() semantics, even if no assertions
933 // are being checked
934 annotated_location = function.source_location();
935 annotated_location.set("user-provided", true);
936 dest.add(goto_programt::make_assumption(false_exprt(), annotated_location));
937 dest.instructions.back().labels.push_back("__VERIFIER_abort");
938 }
939 else if(
940 identifier == "assert" &&
942 {
943 if(arguments.size() != 1)
944 {
946 error() << "'" << identifier << "' expected to have one argument" << eom;
947 throw 0;
948 }
949
950 // let's double-check the type of the argument
951 source_locationt annotated_location = function.source_location();
952 annotated_location.set("user-provided", true);
953 annotated_location.set_property_class(ID_assertion);
954 annotated_location.set_comment(
955 "assertion " + from_expr(ns, identifier, arguments.front()));
957 typecast_exprt::conditional_cast(arguments.front(), bool_typet()),
958 annotated_location));
959
960 if(lhs.is_not_nil())
961 {
963 error() << identifier << " expected not to have LHS" << eom;
964 throw 0;
965 }
966 }
967 else if(
968 identifier == CPROVER_PREFIX "assert" ||
969 identifier == CPROVER_PREFIX "precondition" ||
970 identifier == CPROVER_PREFIX "postcondition")
971 {
972 if(arguments.size() != 2)
973 {
975 error() << "'" << identifier << "' expected to have two arguments" << eom;
976 throw 0;
977 }
978
979 bool is_precondition = identifier == CPROVER_PREFIX "precondition";
980 bool is_postcondition = identifier == CPROVER_PREFIX "postcondition";
981
982 const irep_idt description = get_string_constant(arguments[1]);
983
984 // let's double-check the type of the argument
985 source_locationt annotated_location = function.source_location();
986 if(is_precondition)
987 {
988 annotated_location.set_property_class(ID_precondition);
989 }
990 else if(is_postcondition)
991 {
992 annotated_location.set_property_class(ID_postcondition);
993 }
994 else
995 {
996 annotated_location.set(
997 "user-provided", !function.source_location().is_built_in());
998 annotated_location.set_property_class(ID_assertion);
999 }
1000
1001 annotated_location.set_comment(description);
1002
1005 annotated_location));
1006
1007 if(lhs.is_not_nil())
1008 {
1010 error() << identifier << " expected not to have LHS" << eom;
1011 throw 0;
1012 }
1013 }
1014 else if(identifier == CPROVER_PREFIX "havoc_object")
1015 {
1016 if(arguments.size() != 1)
1017 {
1019 error() << "'" << identifier << "' expected to have one argument" << eom;
1020 throw 0;
1021 }
1022
1023 if(lhs.is_not_nil())
1024 {
1026 error() << identifier << " expected not to have LHS" << eom;
1027 throw 0;
1028 }
1029
1030 codet havoc(ID_havoc_object);
1031 havoc.add_source_location() = function.source_location();
1032 havoc.copy_to_operands(arguments[0]);
1033
1034 dest.add(goto_programt::make_other(havoc, function.source_location()));
1035 }
1036 else if(identifier == CPROVER_PREFIX "printf")
1037 {
1038 do_printf(lhs, function, arguments, dest);
1039 }
1040 else if(identifier == CPROVER_PREFIX "scanf")
1041 {
1042 do_scanf(lhs, function, arguments, dest);
1043 }
1044 else if(
1045 identifier == CPROVER_PREFIX "input" || identifier == "__CPROVER::input")
1046 {
1047 if(lhs.is_not_nil())
1048 {
1050 error() << identifier << " expected not to have LHS" << eom;
1051 throw 0;
1052 }
1053
1054 do_input(function, arguments, dest);
1055 }
1056 else if(
1057 identifier == CPROVER_PREFIX "output" || identifier == "__CPROVER::output")
1058 {
1059 if(lhs.is_not_nil())
1060 {
1062 error() << identifier << " expected not to have LHS" << eom;
1063 throw 0;
1064 }
1065
1066 do_output(function, arguments, dest);
1067 }
1068 else if(
1069 identifier == CPROVER_PREFIX "atomic_begin" ||
1070 identifier == "__CPROVER::atomic_begin" ||
1071 identifier == "java::org.cprover.CProver.atomicBegin:()V" ||
1072 identifier == "__VERIFIER_atomic_begin")
1073 {
1074 do_atomic_begin(lhs, function, arguments, dest);
1075 }
1076 else if(
1077 identifier == CPROVER_PREFIX "atomic_end" ||
1078 identifier == "__CPROVER::atomic_end" ||
1079 identifier == "java::org.cprover.CProver.atomicEnd:()V" ||
1080 identifier == "__VERIFIER_atomic_end")
1081 {
1082 do_atomic_end(lhs, function, arguments, dest);
1083 }
1084 else if(identifier == CPROVER_PREFIX "prob_biased_coin")
1085 {
1086 do_prob_coin(lhs, function, arguments, dest);
1087 }
1088 else if(identifier.starts_with(CPROVER_PREFIX "prob_uniform_"))
1089 {
1090 do_prob_uniform(lhs, function, arguments, dest);
1091 }
1092 else if(
1093 identifier.starts_with("nondet_") ||
1094 identifier.starts_with("__VERIFIER_nondet_"))
1095 {
1096 // make it a side effect if there is an LHS
1097 if(lhs.is_nil())
1098 return;
1099
1100 exprt rhs;
1101
1102 // We need to special-case for _Bool, which
1103 // can only be 0 or 1.
1104 if(lhs.type().id() == ID_c_bool)
1105 {
1107 rhs.set(ID_C_identifier, identifier);
1108 rhs = typecast_exprt(rhs, lhs.type());
1109 }
1110 else
1111 {
1112 rhs = side_effect_expr_nondett(lhs.type(), function.source_location());
1113 rhs.set(ID_C_identifier, identifier);
1114 }
1115
1116 code_assignt assignment(lhs, rhs);
1117 assignment.add_source_location() = function.source_location();
1118 copy(assignment, ASSIGN, dest);
1119 }
1120 else if(identifier.starts_with(CPROVER_PREFIX "uninterpreted_"))
1121 {
1122 // make it a side effect if there is an LHS
1123 if(lhs.is_nil())
1124 return;
1125
1126 if(function.type().get_bool(ID_C_incomplete))
1127 {
1129 error() << "'" << identifier << "' is not declared, "
1130 << "missing type information required to construct call to "
1131 << "uninterpreted function" << eom;
1132 throw 0;
1133 }
1134
1135 const code_typet &function_call_type = to_code_type(function.type());
1137 for(const auto &parameter : function_call_type.parameters())
1138 domain.push_back(parameter.type());
1139 mathematical_function_typet function_type{
1140 domain, function_call_type.return_type()};
1142 symbol_exprt{function.identifier(), function_type}, arguments);
1143
1144 code_assignt assignment(lhs, rhs);
1145 assignment.add_source_location() = function.source_location();
1146 copy(assignment, ASSIGN, dest);
1147 }
1148 else if(identifier == CPROVER_PREFIX "array_equal")
1149 {
1150 do_array_op(ID_array_equal, lhs, function, arguments, dest);
1151 }
1152 else if(identifier == CPROVER_PREFIX "array_set")
1153 {
1154 do_array_op(ID_array_set, lhs, function, arguments, dest);
1155 }
1156 else if(identifier == CPROVER_PREFIX "array_copy")
1157 {
1158 do_array_op(ID_array_copy, lhs, function, arguments, dest);
1159 }
1160 else if(identifier == CPROVER_PREFIX "array_replace")
1161 {
1162 do_array_op(ID_array_replace, lhs, function, arguments, dest);
1163 }
1164 else if(
1165 identifier == "__assert_fail" || identifier == "_assert" ||
1166 identifier == "__assert_c99" || identifier == "_wassert")
1167 {
1168 // __assert_fail is Linux
1169 // These take four arguments:
1170 // "expression", "file.c", line, __func__
1171 // klibc has __assert_fail with 3 arguments
1172 // "expression", "file.c", line
1173
1174 // MingW has
1175 // void _assert (const char*, const char*, int);
1176 // with three arguments:
1177 // "expression", "file.c", line
1178
1179 // This has been seen in Solaris 11.
1180 // Signature:
1181 // void __assert_c99(
1182 // const char *desc, const char *file, int line, const char *func);
1183
1184 // _wassert is Windows. The arguments are
1185 // L"expression", L"file.c", line
1186
1187 if(arguments.size() != 4 && arguments.size() != 3)
1188 {
1190 error() << "'" << identifier << "' expected to have four arguments"
1191 << eom;
1192 throw 0;
1193 }
1194
1195 const irep_idt description =
1196 "assertion " + id2string(get_string_constant(arguments[0]));
1197
1198 source_locationt annotated_location = function.source_location();
1199 annotated_location.set("user-provided", true);
1200 annotated_location.set_property_class(ID_assertion);
1201 annotated_location.set_comment(description);
1202 dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
1203 // we ignore any LHS
1204 }
1205 else if(identifier == "__assert_rtn" || identifier == "__assert")
1206 {
1207 // __assert_rtn has been seen on MacOS;
1208 // __assert is FreeBSD and Solaris 11.
1209 // These take four arguments:
1210 // __func__, "file.c", line, "expression"
1211 // On Solaris 11, it's three arguments:
1212 // "expression", "file", line
1213
1214 irep_idt description;
1215
1216 if(arguments.size() == 4)
1217 {
1218 description = "assertion " + id2string(get_string_constant(arguments[3]));
1219 }
1220 else if(arguments.size() == 3)
1221 {
1222 description = "assertion " + id2string(get_string_constant(arguments[1]));
1223 }
1224 else
1225 {
1227 error() << "'" << identifier << "' expected to have four arguments"
1228 << eom;
1229 throw 0;
1230 }
1231
1232 source_locationt annotated_location = function.source_location();
1233 annotated_location.set("user-provided", true);
1234 annotated_location.set_property_class(ID_assertion);
1235 annotated_location.set_comment(description);
1236 dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
1237 // we ignore any LHS
1238 }
1239 else if(
1240 identifier == "__assert_func" || identifier == "__assert2" ||
1241 identifier == "__assert13")
1242 {
1243 // __assert_func is newlib (used by, e.g., cygwin)
1244 // __assert2 is OpenBSD
1245 // __assert13 is NetBSD
1246 // These take four arguments:
1247 // "file.c", line, __func__, "expression"
1248 if(arguments.size() != 4)
1249 {
1251 error() << "'" << identifier << "' expected to have four arguments"
1252 << eom;
1253 throw 0;
1254 }
1255
1256 irep_idt description;
1257 try
1258 {
1259 description = "assertion " + id2string(get_string_constant(arguments[3]));
1260 }
1261 catch(int)
1262 {
1263 // we might be building newlib, where __assert_func is passed
1264 // a pointer-typed symbol; the warning will still have been
1265 // printed
1266 description = "assertion";
1267 }
1268
1269 source_locationt annotated_location = function.source_location();
1270 annotated_location.set("user-provided", true);
1271 annotated_location.set_property_class(ID_assertion);
1272 annotated_location.set_comment(description);
1273 dest.add(goto_programt::make_assertion(false_exprt(), annotated_location));
1274 // we ignore any LHS
1275 }
1276 else if(identifier == CPROVER_PREFIX "fence")
1277 {
1278 if(arguments.empty())
1279 {
1281 error() << "'" << identifier << "' expected to have at least one argument"
1282 << eom;
1283 throw 0;
1284 }
1285
1286 codet fence(ID_fence);
1287
1288 for(const auto &argument : arguments)
1289 fence.set(get_string_constant(argument), true);
1290
1291 dest.add(goto_programt::make_other(fence, function.source_location()));
1292 }
1293 else if(identifier == "__builtin_prefetch")
1294 {
1295 // does nothing
1296 }
1297 else if(identifier == "__builtin_unreachable")
1298 {
1299 // says something like UNREACHABLE;
1300 }
1301 else if(identifier == ID_gcc_builtin_va_arg)
1302 {
1303 // This does two things.
1304 // 1) Return value of argument.
1305 // This is just dereferencing.
1306 // 2) Move list pointer to next argument.
1307 // This is just an increment.
1308
1309 if(arguments.size() != 1)
1310 {
1312 error() << "'" << identifier << "' expected to have one argument" << eom;
1313 throw 0;
1314 }
1315
1316 exprt list_arg = make_va_list(arguments[0], ns);
1317 const bool va_list_is_void_ptr =
1318 list_arg.type().id() == ID_pointer &&
1319 to_pointer_type(list_arg.type()).base_type().id() == ID_empty;
1320
1321 if(lhs.is_not_nil())
1322 {
1323 exprt list_arg_cast = list_arg;
1324 if(va_list_is_void_ptr)
1325 {
1326 list_arg_cast =
1328 }
1329
1330 typet t = pointer_type(lhs.type());
1332 typecast_exprt{dereference_exprt{std::move(list_arg_cast)}, t}};
1333 rhs.add_source_location() = function.source_location();
1334 dest.add(
1335 goto_programt::make_assignment(lhs, rhs, function.source_location()));
1336 }
1337
1338 exprt list_arg_ptr_arithmetic = typecast_exprt::conditional_cast(
1339 plus_exprt{
1340 (va_list_is_void_ptr
1342 : list_arg),
1344 list_arg.type());
1345 code_assignt assign{list_arg, std::move(list_arg_ptr_arithmetic)};
1346 assign.rhs().set(
1347 ID_C_va_arg_type, to_code_type(function.type()).return_type());
1349 std::move(assign), function.source_location()));
1350 }
1351 else if(identifier == "__builtin_va_copy")
1352 {
1353 if(arguments.size() != 2)
1354 {
1356 error() << "'" << identifier << "' expected to have two arguments" << eom;
1357 throw 0;
1358 }
1359
1360 exprt dest_expr = make_va_list(arguments[0], ns);
1361 const typecast_exprt src_expr(arguments[1], dest_expr.type());
1362
1363 if(!is_assignable(dest_expr))
1364 {
1366 error() << "va_copy argument expected to be lvalue" << eom;
1367 throw 0;
1368 }
1369
1371 dest_expr, src_expr, function.source_location()));
1372 }
1373 else if(identifier == "__builtin_va_start" || identifier == "__va_start")
1374 {
1375 // Set the list argument to be the address of the
1376 // parameter argument.
1377 if(arguments.size() != 2)
1378 {
1380 error() << "'" << identifier << "' expected to have two arguments" << eom;
1381 throw 0;
1382 }
1383
1384 exprt dest_expr = make_va_list(arguments[0], ns);
1385
1386 if(!is_assignable(dest_expr))
1387 {
1389 error() << "va_start argument expected to be lvalue" << eom;
1390 throw 0;
1391 }
1392
1393 if(
1394 dest_expr.type().id() == ID_pointer &&
1395 to_pointer_type(dest_expr.type()).base_type().id() == ID_empty)
1396 {
1397 dest_expr =
1399 }
1400
1402 ID_va_start, dest_expr.type(), function.source_location()};
1403 rhs.add_to_operands(
1404 typecast_exprt{address_of_exprt{arguments[1]}, dest_expr.type()});
1405
1407 std::move(dest_expr), std::move(rhs), function.source_location()));
1408 }
1409 else if(identifier == "__builtin_va_end")
1410 {
1411 // Invalidates the argument. We do so by setting it to NULL.
1412 if(arguments.size() != 1)
1413 {
1415 error() << "'" << identifier << "' expected to have one argument" << eom;
1416 throw 0;
1417 }
1418
1419 exprt dest_expr = make_va_list(arguments[0], ns);
1420
1421 if(!is_assignable(dest_expr))
1422 {
1424 error() << "va_end argument expected to be lvalue" << eom;
1425 throw 0;
1426 }
1427
1428 // our __builtin_va_list is a pointer
1429 if(dest_expr.type().id() == ID_pointer)
1430 {
1431 const auto zero =
1432 zero_initializer(dest_expr.type(), function.source_location(), ns);
1433 CHECK_RETURN(zero.has_value());
1435 dest_expr, *zero, function.source_location()));
1436 }
1437 }
1438 else if(
1439 identifier == "__builtin_isgreater" ||
1440 identifier == "__builtin_isgreaterequal" ||
1441 identifier == "__builtin_isless" || identifier == "__builtin_islessequal" ||
1442 identifier == "__builtin_islessgreater" ||
1443 identifier == "__builtin_isunordered")
1444 {
1445 // these support two double or two float arguments; we call the
1446 // appropriate internal version
1447 if(
1448 arguments.size() != 2 ||
1449 (arguments[0].type() != double_type() &&
1450 arguments[0].type() != float_type()) ||
1451 (arguments[1].type() != double_type() &&
1452 arguments[1].type() != float_type()))
1453 {
1455 error() << "'" << identifier
1456 << "' expected to have two float/double arguments" << eom;
1457 throw 0;
1458 }
1459
1460 exprt::operandst new_arguments = arguments;
1461
1462 bool use_double = arguments[0].type() == double_type();
1463 if(arguments[0].type() != arguments[1].type())
1464 {
1465 if(use_double)
1466 {
1467 new_arguments[1] =
1468 typecast_exprt(new_arguments[1], arguments[0].type());
1469 }
1470 else
1471 {
1472 new_arguments[0] =
1473 typecast_exprt(new_arguments[0], arguments[1].type());
1474 use_double = true;
1475 }
1476 }
1477
1478 code_typet f_type = to_code_type(function.type());
1479 f_type.remove_ellipsis();
1480 const typet &a_t = new_arguments[0].type();
1481 f_type.parameters() =
1483
1484 // replace __builtin_ by CPROVER_PREFIX
1485 std::string name = CPROVER_PREFIX + id2string(identifier).substr(10);
1486 // append d or f for double/float
1487 name += use_double ? 'd' : 'f';
1488
1490 ns.lookup(name).type == f_type,
1491 "builtin declaration should match constructed type");
1492
1493 symbol_exprt new_function = function;
1494 new_function.identifier(name);
1495 new_function.type() = f_type;
1496
1497 code_function_callt function_call(lhs, new_function, new_arguments);
1498 function_call.add_source_location() = function.source_location();
1499
1500 copy(function_call, FUNCTION_CALL, dest);
1501 }
1502 else if(identifier == "alloca" || identifier == "__builtin_alloca")
1503 {
1504 do_alloca(lhs, function, arguments, dest, mode);
1505 }
1506 else
1507 {
1508 do_function_call_symbol(*symbol);
1509
1510 // insert function call
1511 // use symbol->symbol_expr() to ensure we use the type from the symbol table
1512 code_function_callt function_call(
1513 lhs, symbol->symbol_expr().with_source_location(function), arguments);
1514 function_call.add_source_location() = function.source_location();
1515
1516 // remove void-typed assignments, which may have been created when the
1517 // front-end was unable to detect them in type checking for a lack of
1518 // available declarations
1519 if(
1520 lhs.is_not_nil() &&
1521 to_code_type(symbol->type).return_type().id() == ID_empty)
1522 {
1523 function_call.lhs().make_nil();
1524 }
1525
1526 copy(function_call, FUNCTION_CALL, dest);
1527 }
1528}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
static exprt make_va_list(const exprt &expr, const namespacet &ns)
floatbv_typet float_type()
Definition c_types.cpp:177
unsignedbv_typet size_type()
Definition c_types.cpp:50
empty_typet void_type()
Definition c_types.cpp:245
signedbv_typet signed_int_type()
Definition c_types.cpp:22
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:235
signedbv_typet pointer_diff_type()
Definition c_types.cpp:220
unsignedbv_typet unsigned_char_type()
Definition c_types.cpp:127
bitvector_typet c_index_type()
Definition c_types.cpp:16
floatbv_typet double_type()
Definition c_types.cpp:185
Operator to return the address of an object.
Arrays with given size.
Definition std_types.h:806
const exprt & size() const
Definition std_types.h:839
const typet & element_type() const
The type of the elements of the array.
Definition std_types.h:826
The Boolean type.
Definition std_types.h:35
A goto_instruction_codet representing an assignment in the program.
goto_instruction_codet representation of a function call statement.
A goto_instruction_codet representing the declaration that an input of a particular description has a...
A goto_instruction_codet representing the declaration that an output of a particular description has ...
Base type of functions.
Definition std_types.h:582
std::vector< parametert > parameterst
Definition std_types.h:585
const parameterst & parameters() const
Definition std_types.h:698
const typet & return_type() const
Definition std_types.h:688
void remove_ellipsis()
Definition std_types.h:683
Data structure for representing an arbitrary statement in a program.
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
void set_statement(const irep_idt &statement)
Operator to dereference a pointer.
bool starts_with(const char *s) const
equivalent of as_string().starts_with(s)
Definition dstring.h:107
The empty type.
Definition std_types.h:50
Equality.
Definition std_expr.h:1339
Base class for all expressions.
Definition expr.h:57
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition expr.cpp:68
std::vector< exprt > operandst
Definition expr.h:59
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition expr.h:164
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
const source_locationt & source_location() const
Definition expr.h:236
source_locationt & add_source_location()
Definition expr.h:241
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition expr.h:171
The Boolean constant false.
Definition std_expr.h:3135
Application of (mathematical) function.
void do_havoc_slice(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
symbol_table_baset & symbol_table
void do_input(const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest)
void do_array_op(const irep_idt &id, const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
irep_idt get_string_constant(const exprt &expr)
void copy(const codet &code, goto_program_instruction_typet type, goto_programt &dest)
void do_prob_coin(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
struct goto_convertt::targetst targets
symbolt & new_tmp_symbol(const typet &type, const std::string &suffix, goto_programt &dest, const source_locationt &, const irep_idt &mode)
void do_atomic_end(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
virtual void do_function_call_symbol(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
add function calls to function queue for later processing
void do_output(const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest)
void cpp_new_initializer(const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest)
builds a goto program for object initialization after new
void do_printf(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
exprt get_array_argument(const exprt &src)
void do_alloca(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
alloca allocates memory that is freed when leaving the function (and not the block,...
void do_scanf(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
void convert(const codet &code, goto_programt &dest, const irep_idt &mode)
converts 'code' and appends the result to 'dest'
void do_atomic_begin(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
static void replace_new_object(const exprt &object, exprt &dest)
virtual void do_cpp_new(const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest)
clean_expr_resultt clean_expr(exprt &expr, const irep_idt &mode, bool result_is_used=true)
void do_prob_uniform(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
A generic container class for the GOTO intermediate representation of one function.
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
instructionst instructions
The list of instructions in the goto program.
static instructiont make_dead(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
static instructiont make_atomic_end(const source_locationt &l=source_locationt::nil())
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
static instructiont make_other(const goto_instruction_codet &_code, const source_locationt &l=source_locationt::nil())
static instructiont make_atomic_begin(const source_locationt &l=source_locationt::nil())
targett add(instructiont &&instruction)
Adds a given instruction at the end.
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
The trinary if-then-else operator.
Definition std_expr.h:2426
Array index operator.
Definition std_expr.h:1431
bool get_bool(const irep_idt &name) const
Definition irep.cpp:57
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
void set(const irep_idt &name, const irep_idt &value)
Definition irep.h:412
bool is_not_nil() const
Definition irep.h:372
void make_nil()
Definition irep.h:446
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
A type for mathematical functions (do not confuse with functions/methods in code).
Extract member of struct or union.
Definition std_expr.h:2866
source_locationt source_location
Definition message.h:239
mstreamt & error() const
Definition message.h:401
static eomt eom
Definition message.h:289
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
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:91
The null pointer constant.
The plus expression Associativity is not specified.
Definition std_expr.h:1006
const typet & base_type() const
The type of the data what we point to.
A base class for a predicate that indicates that an address range is ok to read or write or both.
A side_effect_exprt that returns a non-deterministically chosen value.
Definition std_code.h:1520
An expression containing a side effect.
Definition std_code.h:1450
const irep_idt & get_statement() const
Definition std_code.h:1472
void set_comment(const irep_idt &comment)
void set_property_class(const irep_idt &property_class)
const irep_idt & get_function() const
void add_pragma(const irep_idt &pragma)
static bool is_built_in(const std::string &s)
const componentst & components() const
Definition std_types.h:146
Expression to hold a symbol (variable).
Definition std_expr.h:132
symbol_exprt & with_source_location(source_locationt location) &
Add the source location from location, if it is non-nil.
Definition std_expr.h:177
void identifier(const irep_idt &identifier)
Definition std_expr.h:160
Symbol table entry.
Definition symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition symbol.cpp:121
typet type
Type of symbol.
Definition symbol.h:31
irep_idt name
The unique identifier.
Definition symbol.h:40
exprt value
Initial value of symbol.
Definition symbol.h:34
const typet & subtype() const
Definition type.h:187
Semantic type conversion.
Definition std_expr.h:1995
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2003
The type of an expression, extends irept.
Definition type.h:29
#define CPROVER_PREFIX
void destruct_locals(const std::list< irep_idt > &vars, goto_programt &dest, const namespacet &ns)
Destructor Calls.
auto type_try_dynamic_cast(TType &base) -> typename detail::expr_try_dynamic_cast_return_typet< T, TType >::type
Try to cast a reference to a generic typet to a specific derived class.
Definition expr_cast.h:135
std::optional< exprt > zero_initializer(const typet &type, const source_locationt &source_location, const namespacet &ns)
Create the equivalent of zero for type type.
Expression Initialization.
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
bool is_assignable(const exprt &expr)
Returns true iff the argument is one of the following:
Definition expr_util.cpp:24
Deprecated expression utility functions.
format_token_listt parse_format_string(const std::string &arg_string)
std::optional< typet > get_type(const format_tokent &token)
Format String Parser.
std::list< format_tokent > format_token_listt
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
Program Transformation.
@ FUNCTION_CALL
@ ASSIGN
@ OTHER
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 'mathematical' expressions.
Mathematical types.
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
exprt object_size(const exprt &pointer)
constant_exprt from_rational(const rationalt &a)
exprt simplify_expr(exprt src, 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
const codet & to_code(const exprt &expr)
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1494
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2024
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:424
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3078
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:221
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:787
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
Definition std_types.h:28
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:887
std::list< irep_idt > temporaries
Identifiers of temporaries introduced while cleaning an expression.
void add(clean_expr_resultt &&other)
void add_temporary(const irep_idt &id)
goto_programt side_effects
Statements implementing side effects of the expression that was subject to cleaning.
Symbol table entry.
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition type.h:208
dstringt irep_idt