CBMC
Loading...
Searching...
No Matches
c_typecheck_expr.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: ANSI-C Language Type Checking
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include <util/arith_tools.h>
13#include <util/bitvector_expr.h>
14#include <util/c_types.h>
15#include <util/config.h>
16#include <util/cprover_prefix.h>
17#include <util/expr_util.h>
18#include <util/floatbv_expr.h>
19#include <util/ieee_float.h>
22#include <util/pointer_expr.h>
25#include <util/range.h>
26#include <util/simplify_expr.h>
28#include <util/suffix.h>
30
32
33#include "anonymous_member.h"
34#include "ansi_c_declaration.h"
35#include "builtin_factory.h"
36#include "c_expr.h"
37#include "c_qualifiers.h"
38#include "c_typecast.h"
39#include "c_typecheck_base.h"
40#include "expr2c.h"
41#include "padding.h"
42#include "type2name.h"
43
44#include <sstream>
45
47{
48 if(expr.id()==ID_already_typechecked)
49 {
50 expr.swap(to_already_typechecked_expr(expr).get_expr());
51 return;
52 }
53
54 // first do sub-nodes
56
57 // now do case-split
59}
60
62{
63 for(auto &op : expr.operands())
65
66 if(expr.id()==ID_div ||
67 expr.id()==ID_mult ||
68 expr.id()==ID_plus ||
69 expr.id()==ID_minus)
70 {
71 if(expr.type().id()==ID_floatbv &&
72 expr.operands().size()==2)
73 {
74 // The rounding mode to be used at compile time is non-obvious.
75 // We'll simply use round to even (0), which is suggested
76 // by Sec. F.7.2 Translation, ISO-9899:1999.
77 expr.operands().resize(3);
78
79 if(expr.id()==ID_div)
80 expr.id(ID_floatbv_div);
81 else if(expr.id()==ID_mult)
82 expr.id(ID_floatbv_mult);
83 else if(expr.id()==ID_plus)
84 expr.id(ID_floatbv_plus);
85 else if(expr.id()==ID_minus)
86 expr.id(ID_floatbv_minus);
87 else
89
90 to_ieee_float_op_expr(expr).rounding_mode() =
92 }
93 }
94}
95
97 const typet &type1,
98 const typet &type2)
99{
100 // read
101 // http://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/Other-Builtins.html
102
103 // check qualifiers first
105 return false;
106
107 if(type1.id()==ID_c_enum_tag)
109 else if(type2.id()==ID_c_enum_tag)
111
112 if(type1.id()==ID_c_enum)
113 {
114 if(type2.id()==ID_c_enum) // both are enums
115 return type1==type2; // compares the tag
116 else if(type2 == to_c_enum_type(type1).underlying_type())
117 return true;
118 }
119 else if(type2.id()==ID_c_enum)
120 {
121 if(type1 == to_c_enum_type(type2).underlying_type())
122 return true;
123 }
124 else if(type1.id()==ID_pointer &&
125 type2.id()==ID_pointer)
126 {
128 to_pointer_type(type1).base_type(), to_pointer_type(type2).base_type());
129 }
130 else if(type1.id()==ID_array &&
131 type2.id()==ID_array)
132 {
134 to_array_type(type1).element_type(),
135 to_array_type(type2).element_type()); // ignore size
136 }
137 else if(type1.id()==ID_code &&
138 type2.id()==ID_code)
139 {
142
144 c_type1.return_type(),
145 c_type2.return_type()))
146 return false;
147
148 if(c_type1.parameters().size()!=c_type2.parameters().size())
149 return false;
150
151 for(std::size_t i=0; i<c_type1.parameters().size(); i++)
153 c_type1.parameters()[i].type(),
154 c_type2.parameters()[i].type()))
155 return false;
156
157 return true;
158 }
159 else
160 {
161 if(type1==type2)
162 {
163 // Need to distinguish e.g. long int from int or
164 // long long int from long int.
165 // The rules appear to match those of C++.
166
167 if(type1.get(ID_C_c_type)==type2.get(ID_C_c_type))
168 return true;
169 }
170 }
171
172 return false;
173}
174
176{
177 if(expr.id()==ID_side_effect)
179 else if(expr.is_constant())
181 else if(expr.id()==ID_infinity)
182 {
183 // ignore
184 }
185 else if(expr.id()==ID_symbol)
187 else if(expr.id()==ID_unary_plus ||
188 expr.id()==ID_unary_minus ||
189 expr.id()==ID_bitnot)
191 else if(expr.id()==ID_not)
193 else if(
194 expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_implies ||
195 expr.id() == ID_xor)
197 else if(expr.id()==ID_address_of)
199 else if(expr.id()==ID_dereference)
201 else if(expr.id()==ID_member)
203 else if(expr.id()==ID_ptrmember)
205 else if(expr.id()==ID_equal ||
206 expr.id()==ID_notequal ||
207 expr.id()==ID_lt ||
208 expr.id()==ID_le ||
209 expr.id()==ID_gt ||
210 expr.id()==ID_ge)
212 else if(expr.id()==ID_index)
214 else if(expr.id()==ID_typecast)
216 else if(expr.id()==ID_sizeof)
218 else if(expr.id()==ID_alignof)
220 else if(
221 expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult ||
222 expr.id() == ID_div || expr.id() == ID_mod || expr.id() == ID_bitand ||
223 expr.id() == ID_bitxor || expr.id() == ID_bitor || expr.id() == ID_bitnand)
224 {
226 }
227 else if(expr.id()==ID_shl || expr.id()==ID_shr)
229 else if(expr.id()==ID_comma)
231 else if(expr.id()==ID_if)
233 else if(expr.id()==ID_code)
234 {
236 error() << "typecheck_expr_main got code: " << expr.pretty() << eom;
237 throw 0;
238 }
239 else if(expr.id()==ID_gcc_builtin_va_arg)
241 else if(expr.id()==ID_cw_va_arg_typeof)
244 {
245 expr.type()=bool_typet();
246 auto &subtypes =
247 (static_cast<type_with_subtypest &>(expr.add(ID_type_arg))).subtypes();
248 PRECONDITION(subtypes.size() == 2);
249 typecheck_type(subtypes[0]);
250 typecheck_type(subtypes[1]);
251 source_locationt source_location=expr.source_location();
252
253 // ignores top-level qualifiers
254 subtypes[0].remove(ID_C_constant);
255 subtypes[0].remove(ID_C_volatile);
256 subtypes[0].remove(ID_C_restricted);
257 subtypes[1].remove(ID_C_constant);
258 subtypes[1].remove(ID_C_volatile);
259 subtypes[1].remove(ID_C_restricted);
260
261 expr = make_boolean_expr(gcc_types_compatible_p(subtypes[0], subtypes[1]));
262 expr.add_source_location()=source_location;
263 }
264 else if(expr.id()==ID_clang_builtin_convertvector)
265 {
266 // This has one operand and a type, and acts like a typecast
267 DATA_INVARIANT(expr.operands().size()==1, "clang_builtin_convertvector has one operand");
268 typecheck_type(expr.type());
269 typecast_exprt tmp(to_unary_expr(expr).op(), expr.type());
270 tmp.add_source_location()=expr.source_location();
271 expr.swap(tmp);
272 }
273 else if(expr.id()==ID_builtin_offsetof)
275 else if(expr.id()==ID_string_constant)
276 {
277 // already fine -- mark as lvalue
278 expr.set(ID_C_lvalue, true);
279 }
280 else if(expr.id()==ID_arguments)
281 {
282 // already fine
283 }
284 else if(expr.id()==ID_designated_initializer)
285 {
286 exprt &designator=static_cast<exprt &>(expr.add(ID_designator));
287
288 Forall_operands(it, designator)
289 {
290 if(it->id()==ID_index)
291 typecheck_expr(to_unary_expr(*it).op()); // still needs typechecking
292 }
293 }
294 else if(expr.id()==ID_initializer_list)
295 {
296 // already fine, just set some type
297 expr.type()=void_type();
298 }
299 else if(
300 expr.id() == ID_forall || expr.id() == ID_exists || expr.id() == ID_lambda)
301 {
302 // These have two operands.
303 // op0 is a tuple with declarations,
304 // op1 is the bound expression
305 auto &binary_expr = to_binary_expr(expr);
306 auto &bindings = binary_expr.op0().operands();
307 auto &where = binary_expr.op1();
308
309 for(const auto &binding : bindings)
310 {
311 if(binding.get(ID_statement) != ID_decl)
312 {
314 error() << "expected declaration as operand of quantifier" << eom;
315 throw 0;
316 }
317 }
318
319 if(has_subexpr(
320 where,
321 [&](const exprt &subexpr)
322 {
325 }))
326 {
328 error() << "quantifier must not contain function calls" << eom;
329 throw 0;
330 }
331
332 // replace declarations by symbol expressions
333 for(auto &binding : bindings)
334 binding = to_code_frontend_decl(to_code(binding)).symbol();
335
336 if(expr.id() == ID_lambda)
337 {
339
340 for(auto &binding : bindings)
341 domain.push_back(binding.type());
342
343 expr.type() = mathematical_function_typet(domain, where.type());
344 }
345 else
346 {
347 expr.type() = bool_typet();
349 }
350 }
351 else if(expr.id()==ID_label)
352 {
353 expr.type()=void_type();
354 }
355 else if(expr.id()==ID_array)
356 {
357 // these pop up as string constants, and are already typed
358 }
359 else if(expr.id()==ID_complex)
360 {
361 // these should only exist as constants,
362 // and should already be typed
363 }
364 else if(expr.id() == ID_complex_real)
365 {
366 const exprt &op = to_unary_expr(expr).op();
367
368 if(op.type().id() != ID_complex)
369 {
370 if(!is_number(op.type()))
371 {
373 error() << "real part retrieval expects numerical operand, "
374 << "but got '" << to_string(op.type()) << "'" << eom;
375 throw 0;
376 }
377
380
382 }
383 else
384 {
386
387 // these are lvalues if the operand is one
388 if(op.get_bool(ID_C_lvalue))
390
391 if(op.type().get_bool(ID_C_constant))
392 complex_real_expr.type().set(ID_C_constant, true);
393
395 }
396 }
397 else if(expr.id() == ID_complex_imag)
398 {
399 const exprt &op = to_unary_expr(expr).op();
400
401 if(op.type().id() != ID_complex)
402 {
403 if(!is_number(op.type()))
404 {
406 error() << "real part retrieval expects numerical operand, "
407 << "but got '" << to_string(op.type()) << "'" << eom;
408 throw 0;
409 }
410
413
415 }
416 else
417 {
419
420 // these are lvalues if the operand is one
421 if(op.get_bool(ID_C_lvalue))
423
424 if(op.type().get_bool(ID_C_constant))
425 complex_imag_expr.type().set(ID_C_constant, true);
426
428 }
429 }
430 else if(expr.id()==ID_generic_selection)
431 {
432 // This is C11.
433 // The operand is already typechecked. Depending
434 // on its type, we return one of the generic associations.
435 auto &op = to_unary_expr(expr).op();
436
437 // This is one of the few places where it's detectable
438 // that we are using "bool" for boolean operators instead
439 // of "int". We convert for this reason.
440 if(op.is_boolean())
442
445
446 // first typecheck all types
447 for(auto &irep : generic_associations)
448 {
449 if(irep.get(ID_type_arg) != ID_default)
450 {
451 typet &type = static_cast<typet &>(irep.add(ID_type_arg));
452 typecheck_type(type);
453 }
454 }
455
456 // first try non-default match
459
460 const typet &op_type = op.type();
461
462 for(const auto &irep : generic_associations)
463 {
464 if(irep.get(ID_type_arg) == ID_default)
465 default_match = static_cast<const exprt &>(irep.find(ID_value));
466 else if(op_type == static_cast<const typet &>(irep.find(ID_type_arg)))
467 {
468 assoc_match = static_cast<const exprt &>(irep.find(ID_value));
469 }
470 }
471
472 if(assoc_match.is_nil())
473 {
474 if(default_match.is_not_nil())
475 expr.swap(default_match);
476 else
477 {
479 error() << "unmatched generic selection: " << to_string(op.type())
480 << eom;
481 throw 0;
482 }
483 }
484 else
485 expr.swap(assoc_match);
486
487 // still need to typecheck the result
488 typecheck_expr(expr);
489 }
490 else if(expr.id()==ID_gcc_asm_input ||
491 expr.id()==ID_gcc_asm_output ||
493 {
494 }
495 else if(expr.id()==ID_lshr || expr.id()==ID_ashr ||
496 expr.id()==ID_assign_lshr || expr.id()==ID_assign_ashr)
497 {
498 // already type checked
499 }
500 else if(
501 expr.id() == ID_C_spec_assigns || expr.id() == ID_C_spec_frees ||
502 expr.id() == ID_target_list)
503 {
504 // already type checked
505 }
507 {
508 typecheck_type(expr.type());
509 if(
510 pointer_offset_bits(bit_cast_expr->type(), *this) ==
511 pointer_offset_bits(bit_cast_expr->op().type(), *this))
512 {
513 exprt tmp = bit_cast_expr->lower();
514 expr.swap(tmp);
515 }
516 else
517 {
519 error() << "bit cast from '" << to_string(bit_cast_expr->op().type())
520 << "' to '" << to_string(expr.type()) << "' not permitted" << eom;
521 throw 0;
522 }
523 }
524 else
525 {
527 error() << "unexpected expression: " << expr.pretty() << eom;
528 throw 0;
529 }
530}
531
533{
534 expr.type() = to_binary_expr(expr).op1().type();
535
536 // make this an l-value if the last operand is one
537 if(to_binary_expr(expr).op1().get_bool(ID_C_lvalue))
538 expr.set(ID_C_lvalue, true);
539}
540
542{
543 // The first parameter is the va_list, and the second
544 // is the type, which will need to be fixed and checked.
545 // The type is given by the parser as type of the expression.
546 auto type_not_permitted = [this](const exprt &expr)
547 {
548 const exprt &arg = to_unary_expr(expr).op();
550 error() << "argument of type '" << to_string(arg.type())
551 << "' not permitted for va_arg" << eom;
552 throw 0;
553 };
554
555 exprt arg = to_unary_expr(expr).op();
557 {
558 // aarch64 ABI mandates that va_list has struct type with member names as
559 // specified
560 const auto &components = follow_tag(*struct_tag_type).components();
561 if(components.size() != 5)
562 type_not_permitted(expr);
563 }
564 else if(arg.type().id() != ID_pointer && arg.type().id() != ID_array)
565 type_not_permitted(expr);
566
567 typet arg_type = expr.type();
569
570 const code_typet new_type{
571 {code_typet::parametert{arg.type()}}, std::move(arg_type)};
572
574 function.add_source_location() = expr.source_location();
575
576 // turn into function call
578 function, {arg}, new_type.return_type(), expr.source_location());
579
580 expr.swap(result);
581
582 // Make sure symbol exists, but we have it return void
583 // to avoid collisions of the same symbol with different
584 // types.
585
587 symbol_type.return_type()=void_type();
588
590 symbol.base_name=ID_gcc_builtin_va_arg;
591
592 symbol_table.insert(std::move(symbol));
593}
594
596{
597 // used in Code Warrior via
598 //
599 // __va_arg( <Symbol>, _var_arg_typeof( <Typ> ) )
600 //
601 // where __va_arg is declared as
602 //
603 // extern void* __va_arg(void*, int);
604
605 typet &type=static_cast<typet &>(expr.add(ID_type_arg));
606 typecheck_type(type);
607
608 // these return an integer
609 expr.type()=signed_int_type();
610}
611
613{
614 // these need not be constant, due to array indices!
615
616 if(!expr.operands().empty())
617 {
619 error() << "builtin_offsetof expects no operands" << eom;
620 throw 0;
621 }
622
623 typet &type=static_cast<typet &>(expr.add(ID_type_arg));
624 typecheck_type(type);
625
626 const exprt &member = static_cast<const exprt &>(expr.add(ID_designator));
627
629
630 for(const auto &op : member.operands())
631 {
632 if(op.id() == ID_member)
633 {
634 if(type.id() != ID_union_tag && type.id() != ID_struct_tag)
635 {
637 error() << "offsetof of member expects struct/union type, "
638 << "but got '" << to_string(type) << "'" << eom;
639 throw 0;
640 }
641
642 bool found=false;
643 irep_idt component_name = op.get(ID_component_name);
644
645 while(!found)
646 {
647 PRECONDITION(type.id() == ID_union_tag || type.id() == ID_struct_tag);
648
651
652 // direct member?
653 if(struct_union_type.has_component(component_name))
654 {
655 found=true;
656
657 if(type.id() == ID_struct_tag)
658 {
660 follow_tag(to_struct_tag_type(type)), component_name, *this);
661
662 if(!o_opt.has_value())
663 {
665 error() << "offsetof failed to determine offset of '"
666 << component_name << "'" << eom;
667 throw 0;
668 }
669
671 result,
673 }
674
675 type=struct_union_type.get_component(component_name).type();
676 }
677 else
678 {
679 // maybe anonymous?
680 bool found2=false;
681
682 for(const auto &c : struct_union_type.components())
683 {
684 if(
685 c.get_anonymous() &&
686 (c.type().id() == ID_struct_tag || c.type().id() == ID_union_tag))
687 {
688 if(has_component_rec(c.type(), component_name, *this))
689 {
690 if(type.id() == ID_struct_tag)
691 {
693 follow_tag(to_struct_tag_type(type)), c.get_name(), *this);
694
695 if(!o_opt.has_value())
696 {
698 error() << "offsetof failed to determine offset of '"
699 << component_name << "'" << eom;
700 throw 0;
701 }
702
704 result,
706 o_opt.value(), size_type()));
707 }
708
709 typet tmp = c.type();
710 type=tmp;
712 type.id() == ID_union_tag || type.id() == ID_struct_tag);
713 found2=true;
714 break; // we run into another iteration of the outer loop
715 }
716 }
717 }
718
719 if(!found2)
720 {
722 error() << "offset-of of member failed to find component '"
723 << component_name << "' in '" << to_string(type) << "'"
724 << eom;
725 throw 0;
726 }
727 }
728 }
729 }
730 else if(op.id() == ID_index)
731 {
732 if(type.id()!=ID_array)
733 {
735 error() << "offsetof of index expects array type" << eom;
736 throw 0;
737 }
738
739 exprt index = to_unary_expr(op).op();
740
741 // still need to typecheck index
742 typecheck_expr(index);
743
744 auto element_size_opt =
745 size_of_expr(to_array_type(type).element_type(), *this);
746
747 if(!element_size_opt.has_value())
748 {
750 error() << "offsetof failed to determine array element size" << eom;
751 throw 0;
752 }
753
755
757
758 typet tmp = to_array_type(type).element_type();
759 type=tmp;
760 }
761 }
762
763 // We make an effort to produce a constant,
764 // but this may depend on variables
765 simplify(result, *this);
766 result.add_source_location()=expr.source_location();
767
768 expr.swap(result);
769}
770
772{
773 if(expr.id()==ID_side_effect &&
775 {
776 // don't do function operand
777 typecheck_expr(to_binary_expr(expr).op1()); // arguments
778 }
779 else if(expr.id()==ID_side_effect &&
781 {
783 }
784 else if(
785 expr.id() == ID_forall || expr.id() == ID_exists || expr.id() == ID_lambda)
786 {
787 // These introduce new symbols, which need to be added to the symbol table
788 // before the second operand is typechecked.
789
790 auto &binary_expr = to_binary_expr(expr);
791 auto &bindings = binary_expr.op0().operands();
792
793 for(auto &binding : bindings)
794 {
795 ansi_c_declarationt &declaration = to_ansi_c_declaration(binding);
796
797 typecheck_declaration(declaration);
798
799 if(declaration.declarators().size() != 1)
800 {
802 error() << "forall/exists expects one declarator exactly" << eom;
803 throw 0;
804 }
805
806 irep_idt identifier = declaration.declarators().front().get_name();
807
808 // look it up
809 symbol_table_baset::symbolst::const_iterator s_it =
810 symbol_table.symbols.find(identifier);
811
812 if(s_it == symbol_table.symbols.end())
813 {
815 error() << "failed to find bound symbol `" << identifier
816 << "' in symbol table" << eom;
817 throw 0;
818 }
819
820 const symbolt &symbol = s_it->second;
821
822 if(
823 symbol.is_type || symbol.is_extern || symbol.is_static_lifetime ||
824 !is_complete_type(symbol.type) || symbol.type.id() == ID_code)
825 {
827 error() << "unexpected quantified symbol" << eom;
828 throw 0;
829 }
830
831 code_frontend_declt decl(symbol.symbol_expr());
832 decl.add_source_location() = declaration.source_location();
833
834 binding = decl;
835 }
836
838 }
839 else
840 {
841 Forall_operands(it, expr)
842 typecheck_expr(*it);
843 }
844}
845
847{
848 irep_idt identifier=to_symbol_expr(expr).get_identifier();
849
850 // Is it a parameter? We do this while checking parameter lists.
851 id_type_mapt::const_iterator p_it=parameter_map.find(identifier);
852 if(p_it!=parameter_map.end())
853 {
854 // yes
855 expr.type()=p_it->second;
856 expr.set(ID_C_lvalue, true);
857 return;
858 }
859
860 // renaming via GCC asm label
861 asm_label_mapt::const_iterator entry=
862 asm_label_map.find(identifier);
863 if(entry!=asm_label_map.end())
864 {
865 identifier=entry->second;
866 to_symbol_expr(expr).set_identifier(identifier);
867 }
868
869 // look it up
870 const symbolt *symbol_ptr;
871 if(lookup(identifier, symbol_ptr))
872 {
874 error() << "failed to find symbol '" << identifier << "'" << eom;
875 throw 0;
876 }
877
878 const symbolt &symbol=*symbol_ptr;
879
880 if(symbol.is_type)
881 {
883 error() << "did not expect a type symbol here, but got '"
884 << symbol.display_name() << "'" << eom;
885 throw 0;
886 }
887
888 // save the source location
889 source_locationt source_location=expr.source_location();
890
891 if(symbol.is_macro)
892 {
893 // preserve enum key
894 #if 0
895 irep_idt base_name=expr.get(ID_C_base_name);
896 #endif
897
898 follow_macros(expr);
899
900 #if 0
901 if(expr.is_constant() && !base_name.empty())
902 expr.set(ID_C_cformat, base_name);
903 else
904 #endif
905 typecheck_expr(expr);
906
907 // preserve location
908 expr.add_source_location()=source_location;
909 }
910 else if(identifier.starts_with(CPROVER_PREFIX "constant_infinity"))
911 {
912 expr=infinity_exprt(symbol.type);
913
914 // put it back
915 expr.add_source_location()=source_location;
916 }
917 else if(identifier=="__func__" ||
918 identifier=="__FUNCTION__" ||
919 identifier=="__PRETTY_FUNCTION__")
920 {
921 // __func__ is an ANSI-C standard compliant hack to get the function name
922 // __FUNCTION__ and __PRETTY_FUNCTION__ are GCC-specific
923 string_constantt s(source_location.get_function());
924 s.add_source_location()=source_location;
925 s.set(ID_C_lvalue, true);
926 expr.swap(s);
927 }
928 else
929 {
930 expr=symbol.symbol_expr();
931
932 // put it back
933 expr.add_source_location()=source_location;
934
935 if(symbol.is_lvalue)
936 expr.set(ID_C_lvalue, true);
937
938 if(expr.type().id()==ID_code) // function designator
939 { // special case: this is sugar for &f
940 address_of_exprt tmp(expr, pointer_type(expr.type()));
941 tmp.set(ID_C_implicit, true);
942 tmp.add_source_location()=expr.source_location();
943 expr=tmp;
944 }
945 }
946}
947
949 side_effect_exprt &expr)
950{
951 codet &code = to_code(to_unary_expr(expr).op());
952
953 // the type is the type of the last statement in the
954 // block, but do worry about labels!
955
956 codet &last=to_code_block(code).find_last_statement();
957
958 irep_idt last_statement=last.get_statement();
959
960 if(last_statement==ID_expression)
961 {
962 PRECONDITION(last.operands().size() == 1);
963 exprt &op=last.op0();
964
965 // arrays here turn into pointers (array decay)
966 if(op.type().id()==ID_array)
968 op, pointer_type(to_array_type(op.type()).element_type()));
969
970 expr.type()=op.type();
971 }
972 else
973 {
974 // we used to do this, but don't expect it any longer
975 PRECONDITION(last_statement != ID_function_call);
976
977 expr.type()=typet(ID_empty);
978 }
979}
980
982{
983 typet type;
984
985 // these come in two flavors: with zero operands, for a type,
986 // and with one operand, for an expression.
987 PRECONDITION(expr.operands().size() <= 1);
988
989 if(expr.operands().empty())
990 {
991 type.swap(static_cast<typet &>(expr.add(ID_type_arg)));
992 typecheck_type(type);
993 }
994 else
995 {
996 const exprt &op = to_unary_expr(as_const(expr)).op();
997 // This is one of the few places where it's detectable
998 // that we are using "bool" for boolean operators instead
999 // of "int". We convert for this reason.
1000 if(op.is_boolean())
1001 type = signed_int_type();
1002 else
1003 type = op.type();
1004 }
1005
1007
1008 if(type.id()==ID_c_bit_field)
1009 {
1010 // only comma or side-effect expressions are permitted
1011 const exprt &op = skip_typecast(to_unary_expr(as_const(expr)).op());
1012 if(op.id() == ID_comma || op.id() == ID_side_effect)
1013 {
1016 {
1018 (bf_type.get_width() + config.ansi_c.char_width - 1) /
1019 config.ansi_c.char_width,
1020 size_type());
1021 }
1022 else
1023 {
1024 auto size_of_opt = size_of_expr(bf_type.underlying_type(), *this);
1025
1026 if(!size_of_opt.has_value())
1027 {
1029 error() << "type has no size: "
1030 << to_string(bf_type.underlying_type()) << eom;
1031 throw 0;
1032 }
1033
1034 new_expr = size_of_opt.value();
1035 }
1036 }
1037 else
1038 {
1040 error() << "sizeof cannot be applied to bit fields" << eom;
1041 throw 0;
1042 }
1043 }
1044 else if(type.id() == ID_bool)
1045 {
1047 error() << "sizeof cannot be applied to single bits" << eom;
1048 throw 0;
1049 }
1050 else if(type.id() == ID_empty)
1051 {
1052 // This is a gcc extension.
1053 // https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.html
1055 }
1056 else
1057 {
1058 if(
1059 (type.id() == ID_struct_tag &&
1060 follow_tag(to_struct_tag_type(type)).is_incomplete()) ||
1061 (type.id() == ID_union_tag &&
1062 follow_tag(to_union_tag_type(type)).is_incomplete()) ||
1063 (type.id() == ID_c_enum_tag &&
1064 follow_tag(to_c_enum_tag_type(type)).is_incomplete()) ||
1065 (type.id() == ID_array && to_array_type(type).is_incomplete()))
1066 {
1068 error() << "invalid application of \'sizeof\' to an incomplete type\n\t\'"
1069 << to_string(type) << "\'" << eom;
1070 throw 0;
1071 }
1072
1073 auto size_of_opt = size_of_expr(type, *this);
1074
1075 if(!size_of_opt.has_value())
1076 {
1078 error() << "type has no size: " << to_string(type) << eom;
1079 throw 0;
1080 }
1081
1082 new_expr = size_of_opt.value();
1083 }
1084
1085 source_locationt location = expr.source_location();
1086 new_expr.swap(expr);
1087 expr.add_source_location() = location;
1088 expr.add(ID_C_c_sizeof_type)=type;
1089
1090 // The type may contain side-effects.
1091 if(!clean_code.empty())
1092 {
1094 ID_statement_expression, void_type(), location);
1096 decl_block.set_statement(ID_decl_block);
1097 side_effect_expr.copy_to_operands(decl_block);
1098 clean_code.clear();
1099
1100 // We merge the side-effect into the operand of the typecast,
1101 // using a comma-expression.
1102 // I.e., (type)e becomes (type)(side-effect, e)
1103 // It is not obvious whether the type or 'e' should be evaluated
1104 // first.
1105
1107 binary_exprt{std::move(side_effect_expr), ID_comma, expr, expr.type()}
1108 .with_source_location(location);
1109 expr.swap(comma_expr);
1110 }
1111}
1112
1114{
1116
1117 if(expr.operands().size()==1)
1118 argument_type = to_unary_expr(expr).op().type();
1119 else
1120 {
1121 typet &op_type=static_cast<typet &>(expr.add(ID_type_arg));
1124 }
1125
1126 // we only care about the type
1128
1130 tmp.add_source_location()=expr.source_location();
1131
1132 expr.swap(tmp);
1133}
1134
1136{
1137 exprt &op = to_unary_expr(expr).op();
1138
1139 typecheck_type(expr.type());
1140
1141 // The type may contain side-effects.
1142 if(!clean_code.empty())
1143 {
1147 decl_block.set_statement(ID_decl_block);
1148 side_effect_expr.copy_to_operands(decl_block);
1149 clean_code.clear();
1150
1151 // We merge the side-effect into the operand of the typecast,
1152 // using a comma-expression.
1153 // I.e., (type)e becomes (type)(side-effect, e)
1154 // It is not obvious whether the type or 'e' should be evaluated
1155 // first.
1156
1158 std::move(side_effect_expr), ID_comma, op, op.type()};
1159 op.swap(comma_expr);
1160 }
1161
1162 const typet expr_type = expr.type();
1163
1164 if(
1165 expr_type.id() == ID_union_tag && expr_type != op.type() &&
1166 op.id() != ID_initializer_list)
1167 {
1168 // This is a GCC extension. It's either a 'temporary union',
1169 // where the argument is one of the member types.
1170
1171 // This is one of the few places where it's detectable
1172 // that we are using "bool" for boolean operators instead
1173 // of "int". We convert for this reason.
1174 if(op.is_boolean())
1175 op = typecast_exprt(op, signed_int_type());
1176
1177 // we need to find a member with the right type
1179 for(const auto &c : union_type.components())
1180 {
1181 if(c.type() == op.type())
1182 {
1183 // found! build union constructor
1184 union_exprt union_expr(c.get_name(), op, expr.type());
1185 union_expr.add_source_location()=expr.source_location();
1186 expr=union_expr;
1187 expr.set(ID_C_lvalue, true);
1188 return;
1189 }
1190 }
1191
1192 // not found, complain
1194 error() << "type cast to union: type '" << to_string(op.type())
1195 << "' not found in union" << eom;
1196 throw 0;
1197 }
1198
1199 // We allow (TYPE){ initializer_list }
1200 // This is called "compound literal", and is syntactic
1201 // sugar for a (possibly local) declaration.
1202 if(op.id()==ID_initializer_list)
1203 {
1204 // just do a normal initialization
1205 do_initializer(op, expr.type(), false);
1206
1207 // This produces a struct-expression,
1208 // union-expression, array-expression,
1209 // or an expression for a pointer or scalar.
1210 // We produce a compound_literal expression.
1212 tmp.copy_to_operands(op);
1213
1214 // handle the case of TYPE being an array with unspecified size
1215 if(op.id()==ID_array &&
1216 expr.type().id()==ID_array &&
1217 to_array_type(expr.type()).size().is_nil())
1218 tmp.type()=op.type();
1219
1220 expr=tmp;
1221 expr.set(ID_C_lvalue, true); // these are l-values
1222 return;
1223 }
1224
1225 // a cast to void is always fine
1226 if(expr_type.id()==ID_empty)
1227 return;
1228
1229 const typet op_type = op.type();
1230
1231 // cast to same type?
1232 if(expr_type == op_type)
1233 return; // it's ok
1234
1235 // vectors?
1236
1237 if(expr_type.id()==ID_vector)
1238 {
1239 // we are generous -- any vector to vector is fine
1240 if(op_type.id()==ID_vector)
1241 return;
1242 else if(op_type.id()==ID_signedbv ||
1243 op_type.id()==ID_unsignedbv)
1244 return;
1245 }
1246
1248 {
1250 error() << "type cast to '" << to_string(expr_type) << "' is not permitted"
1251 << eom;
1252 throw 0;
1253 }
1254
1256 {
1257 }
1258 else if(op_type.id()==ID_array)
1259 {
1260 // This is the promotion from an array
1261 // to a pointer to the first element.
1263 if(error_opt.has_value())
1265
1266 index_exprt index(op, from_integer(0, c_index_type()));
1267 op=address_of_exprt(index);
1268 }
1269 else if(op_type.id()==ID_empty)
1270 {
1271 if(expr_type.id()!=ID_empty)
1272 {
1274 error() << "type cast from void only permitted to void, but got '"
1275 << to_string(expr.type()) << "'" << eom;
1276 throw 0;
1277 }
1278 }
1279 else if(op_type.id()==ID_vector)
1280 {
1283
1284 // gcc allows conversion of a vector of size 1 to
1285 // an integer/float of the same size
1286 if((expr_type.id()==ID_signedbv ||
1287 expr_type.id()==ID_unsignedbv) &&
1290 {
1291 }
1292 else
1293 {
1295 error() << "type cast from vector to '" << to_string(expr.type())
1296 << "' not permitted" << eom;
1297 throw 0;
1298 }
1299 }
1300 else
1301 {
1303 error() << "type cast from '" << to_string(op_type) << "' not permitted"
1304 << eom;
1305 throw 0;
1306 }
1307
1308 // The new thing is an lvalue if the previous one is
1309 // an lvalue and it's just a pointer type cast.
1310 // This isn't really standard conformant!
1311 // Note that gcc says "warning: target of assignment not really an lvalue;
1312 // this will be a hard error in the future", i.e., we
1313 // can hope that the code below will one day simply go away.
1314
1315 // Current versions of gcc in fact refuse to do this! Yay!
1316
1317 if(op.get_bool(ID_C_lvalue))
1318 {
1319 if(expr_type.id()==ID_pointer)
1320 expr.set(ID_C_lvalue, true);
1321 }
1322}
1323
1328
1330{
1331 exprt &array_expr = to_binary_expr(expr).op0();
1332 exprt &index_expr = to_binary_expr(expr).op1();
1333
1334 // we might have to swap them
1335
1336 {
1337 const typet &array_type = array_expr.type();
1338 const typet &index_type = index_expr.type();
1339
1340 if(
1341 array_type.id() != ID_array && array_type.id() != ID_pointer &&
1342 array_type.id() != ID_vector &&
1343 (index_type.id() == ID_array || index_type.id() == ID_pointer ||
1344 index_type.id() == ID_vector))
1345 std::swap(array_expr, index_expr);
1346 }
1347
1349
1350 // array_expr is a reference to one of expr.operands(), when that vector is
1351 // swapped below the reference is no longer valid. final_array_type exists
1352 // beyond that point so can't be a reference
1353 const typet final_array_type = array_expr.type();
1354
1355 if(final_array_type.id()==ID_array ||
1357 {
1358 expr.type() = to_type_with_subtype(final_array_type).subtype();
1359
1360 if(array_expr.get_bool(ID_C_lvalue))
1361 expr.set(ID_C_lvalue, true);
1362
1363 if(final_array_type.get_bool(ID_C_constant))
1364 expr.type().set(ID_C_constant, true);
1365 }
1366 else if(final_array_type.id()==ID_pointer)
1367 {
1368 // p[i] is syntactic sugar for *(p+i)
1369
1372 std::swap(summands, expr.operands());
1373 expr.add_to_operands(plus_exprt(std::move(summands), array_expr.type()));
1374 expr.id(ID_dereference);
1375 expr.set(ID_C_lvalue, true);
1376 expr.type() = to_pointer_type(final_array_type).base_type();
1377 }
1378 else
1379 {
1381 error() << "operator [] must take array/vector or pointer but got '"
1382 << to_string(array_expr.type()) << "'" << eom;
1383 throw 0;
1384 }
1385}
1386
1388{
1389 // equality and disequality on float is not mathematical equality!
1390 if(expr.op0().type().id() == ID_floatbv)
1391 {
1392 if(expr.id()==ID_equal)
1393 expr.id(ID_ieee_float_equal);
1394 else if(expr.id()==ID_notequal)
1396 }
1397}
1398
1401{
1402 exprt &op0=expr.op0();
1403 exprt &op1=expr.op1();
1404
1405 const typet o_type0=op0.type();
1406 const typet o_type1=op1.type();
1407
1408 if(o_type0.id() == ID_vector || o_type1.id() == ID_vector)
1409 {
1411 return;
1412 }
1413
1414 expr.type()=bool_typet();
1415
1416 if(expr.id()==ID_equal || expr.id()==ID_notequal)
1417 {
1418 if(o_type0 == o_type1)
1419 {
1420 if(o_type0.id() != ID_array)
1421 {
1422 adjust_float_rel(expr);
1423 return; // no promotion necessary
1424 }
1425 }
1426 }
1427
1429
1430 const typet &type0=op0.type();
1431 const typet &type1=op1.type();
1432
1433 if(type0==type1)
1434 {
1435 if(is_number(type0))
1436 {
1437 adjust_float_rel(expr);
1438 return;
1439 }
1440
1441 if(type0.id()==ID_pointer)
1442 {
1443 if(expr.id()==ID_equal || expr.id()==ID_notequal)
1444 return;
1445
1446 if(expr.id()==ID_le || expr.id()==ID_lt ||
1447 expr.id()==ID_ge || expr.id()==ID_gt)
1448 return;
1449 }
1450
1451 if(type0.id()==ID_string_constant)
1452 {
1453 if(expr.id()==ID_equal || expr.id()==ID_notequal)
1454 return;
1455 }
1456 }
1457 else
1458 {
1459 // pointer and zero
1460 if(type0.id() == ID_pointer && simplify_expr(op1, *this) == 0)
1461 {
1463 return;
1464 }
1465
1466 if(type1.id() == ID_pointer && simplify_expr(op0, *this) == 0)
1467 {
1469 return;
1470 }
1471
1472 // pointer and integer
1473 if(type0.id()==ID_pointer && is_number(type1))
1474 {
1475 op1 = typecast_exprt(op1, type0);
1476 return;
1477 }
1478
1479 if(type1.id()==ID_pointer && is_number(type0))
1480 {
1481 op0 = typecast_exprt(op0, type1);
1482 return;
1483 }
1484
1485 if(type0.id()==ID_pointer && type1.id()==ID_pointer)
1486 {
1487 op1 = typecast_exprt(op1, type0);
1488 return;
1489 }
1490 }
1491
1493 error() << "operator '" << expr.id() << "' not defined for types '"
1494 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
1495 << eom;
1496 throw 0;
1497}
1498
1500{
1501 const typet &o_type0 = as_const(expr).op0().type();
1502 const typet &o_type1 = as_const(expr).op1().type();
1503
1504 if(o_type0.id() != ID_vector || o_type0 != o_type1)
1505 {
1507 error() << "vector operator '" << expr.id() << "' not defined for types '"
1508 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
1509 << eom;
1510 throw 0;
1511 }
1512
1513 // Comparisons between vectors produce a vector of integers of the same width
1514 // with the same dimension.
1515 auto subtype_width =
1516 to_bitvector_type(to_vector_type(o_type0).element_type()).get_width();
1517 expr.type() = vector_typet{
1518 to_vector_type(o_type0).index_type(),
1520 to_vector_type(o_type0).size()};
1521
1522 // Replace the id as the semantics of these are point-wise application (and
1523 // the result is not of bool type).
1524 if(expr.id() == ID_notequal)
1525 expr.id(ID_vector_notequal);
1526 else
1527 expr.id("vector-" + id2string(expr.id()));
1528}
1529
1531{
1532 auto &op = to_unary_expr(expr).op();
1533 const typet &op0_type = op.type();
1534
1535 if(op0_type.id() == ID_array)
1536 {
1537 // a->f is the same as a[0].f
1538 exprt zero = from_integer(0, c_index_type());
1539 index_exprt index_expr(op, zero, to_array_type(op0_type).element_type());
1540 index_expr.set(ID_C_lvalue, true);
1541 op.swap(index_expr);
1542 }
1543 else if(op0_type.id() == ID_pointer)
1544 {
1545 // turn x->y into (*x).y
1549 op.swap(deref_expr);
1550 }
1551 else
1552 {
1554 error() << "ptrmember operator requires pointer or array type "
1555 "on left hand side, but got '"
1556 << to_string(op0_type) << "'" << eom;
1557 throw 0;
1558 }
1559
1560 expr.id(ID_member);
1562}
1563
1565{
1566 exprt &op0 = to_unary_expr(expr).op();
1567 typet type=op0.type();
1568
1569 if(type.id() != ID_struct_tag && type.id() != ID_union_tag)
1570 {
1572 error() << "member operator requires structure type "
1573 "on left hand side but got '"
1574 << to_string(type) << "'" << eom;
1575 throw 0;
1576 }
1577
1580
1581 if(struct_union_type.is_incomplete())
1582 {
1584 error() << "member operator got incomplete " << type.id()
1585 << " type on left hand side" << eom;
1586 throw 0;
1587 }
1588
1589 const irep_idt &component_name=
1590 expr.get(ID_component_name);
1591
1592 // first try to find directly
1594 struct_union_type.get_component(component_name);
1595
1596 // if that fails, search the anonymous members
1597
1598 if(component.is_nil())
1599 {
1600 exprt tmp=get_component_rec(op0, component_name, *this);
1601
1602 if(tmp.is_nil())
1603 {
1604 // give up
1606 error() << "member '" << component_name << "' not found in '"
1607 << to_string(type) << "'" << eom;
1608 throw 0;
1609 }
1610
1611 // done!
1612 expr.swap(tmp);
1613 return;
1614 }
1615
1616 expr.type()=component.type();
1617
1618 if(op0.get_bool(ID_C_lvalue))
1619 expr.set(ID_C_lvalue, true);
1620
1621 if(
1622 op0.type().get_bool(ID_C_constant) ||
1624 {
1625 expr.type().set(ID_C_constant, true);
1626 }
1627
1628 // copy method identifier
1629 const irep_idt &identifier=component.get(ID_C_identifier);
1630
1631 if(!identifier.empty())
1632 expr.set(ID_C_identifier, identifier);
1633
1634 const irep_idt &access=component.get_access();
1635
1636 if(access==ID_private)
1637 {
1639 error() << "member '" << component_name << "' is " << access << eom;
1640 throw 0;
1641 }
1642}
1643
1645{
1646 exprt::operandst &operands=expr.operands();
1647
1648 PRECONDITION(operands.size() == 3);
1649
1650 // copy (save) original types
1651 const typet o_type0=operands[0].type();
1652 const typet o_type1=operands[1].type();
1653 const typet o_type2=operands[2].type();
1654
1655 implicit_typecast_bool(operands[0]);
1656
1657 if(o_type1.id() == ID_empty || o_type2.id() == ID_empty)
1658 {
1659 operands[1] = typecast_exprt::conditional_cast(operands[1], void_type());
1660 operands[2] = typecast_exprt::conditional_cast(operands[2], void_type());
1661 expr.type() = void_type();
1662 return;
1663 }
1664
1665 if(
1667 {
1668 implicit_typecast(operands[1], pointer_type(string_constant->char_type()));
1669 }
1670
1671 if(
1673 {
1674 implicit_typecast(operands[2], pointer_type(string_constant->char_type()));
1675 }
1676
1677 if(operands[1].type().id()==ID_pointer &&
1678 operands[2].type().id()!=ID_pointer)
1679 implicit_typecast(operands[2], operands[1].type());
1680 else if(operands[2].type().id()==ID_pointer &&
1681 operands[1].type().id()!=ID_pointer)
1682 implicit_typecast(operands[1], operands[2].type());
1683
1684 if(operands[1].type().id()==ID_pointer &&
1685 operands[2].type().id()==ID_pointer &&
1686 operands[1].type()!=operands[2].type())
1687 {
1688 exprt tmp1=simplify_expr(operands[1], *this);
1689 exprt tmp2=simplify_expr(operands[2], *this);
1690
1691 // is one of them void * AND null? Convert that to the other.
1692 // (at least that's how GCC behaves)
1693 if(
1694 to_pointer_type(operands[1].type()).base_type().id() == ID_empty &&
1695 tmp1.is_constant() && to_constant_expr(tmp1).is_null_pointer())
1696 {
1697 implicit_typecast(operands[1], operands[2].type());
1698 }
1699 else if(
1700 to_pointer_type(operands[2].type()).base_type().id() == ID_empty &&
1701 tmp2.is_constant() && to_constant_expr(tmp2).is_null_pointer())
1702 {
1703 implicit_typecast(operands[2], operands[1].type());
1704 }
1705 else if(
1706 to_pointer_type(operands[1].type()).base_type().id() != ID_code ||
1707 to_pointer_type(operands[2].type()).base_type().id() != ID_code)
1708 {
1709 // Make it void *.
1710 // gcc and clang issue a warning for this.
1711 expr.type() = pointer_type(void_type());
1712 implicit_typecast(operands[1], expr.type());
1713 implicit_typecast(operands[2], expr.type());
1714 }
1715 else
1716 {
1717 // maybe functions without parameter lists
1718 const code_typet &c_type1 =
1719 to_code_type(to_pointer_type(operands[1].type()).base_type());
1720 const code_typet &c_type2 =
1721 to_code_type(to_pointer_type(operands[2].type()).base_type());
1722
1723 if(c_type1.return_type()==c_type2.return_type())
1724 {
1725 if(c_type1.parameters().empty() && c_type1.has_ellipsis())
1726 implicit_typecast(operands[1], operands[2].type());
1727 else if(c_type2.parameters().empty() && c_type2.has_ellipsis())
1728 implicit_typecast(operands[2], operands[1].type());
1729 }
1730 }
1731 }
1732
1733 if(operands[1].type().id()==ID_empty ||
1734 operands[2].type().id()==ID_empty)
1735 {
1736 expr.type()=void_type();
1737 return;
1738 }
1739
1740 if(
1741 operands[1].type() != operands[2].type() ||
1742 operands[1].type().id() == ID_array)
1743 {
1744 implicit_typecast_arithmetic(operands[1], operands[2]);
1745 }
1746
1747 if(operands[1].type() == operands[2].type())
1748 {
1749 expr.type()=operands[1].type();
1750
1751 // GCC says: "A conditional expression is a valid lvalue
1752 // if its type is not void and the true and false branches
1753 // are both valid lvalues."
1754
1755 if(operands[1].get_bool(ID_C_lvalue) &&
1756 operands[2].get_bool(ID_C_lvalue))
1757 expr.set(ID_C_lvalue, true);
1758
1759 return;
1760 }
1761
1763 error() << "operator ?: not defined for types '" << to_string(o_type1)
1764 << "' and '" << to_string(o_type2) << "'" << eom;
1765 throw 0;
1766}
1767
1769 side_effect_exprt &expr)
1770{
1771 // x ? : y is almost the same as x ? x : y,
1772 // but not quite, as x is evaluated only once
1773
1774 exprt::operandst &operands=expr.operands();
1775
1776 if(operands.size()!=2)
1777 {
1779 error() << "gcc conditional_expr expects two operands" << eom;
1780 throw 0;
1781 }
1782
1783 // use typechecking code for "if"
1784
1785 if_exprt if_expr(operands[0], operands[0], operands[1]);
1786 if_expr.add_source_location()=expr.source_location();
1787
1789
1790 // copy the result
1791 operands[0] = if_expr.true_case();
1792 operands[1] = if_expr.false_case();
1793 expr.type()=if_expr.type();
1794}
1795
1797{
1798 exprt &op = to_unary_expr(expr).op();
1799
1801
1802 if(error_opt.has_value())
1804
1805 // special case: address of label
1806 if(op.id()==ID_label)
1807 {
1808 expr.type()=pointer_type(void_type());
1809
1810 // remember the label
1812 return;
1813 }
1814
1815 // special case: address of function designator
1816 // ANSI-C 99 section 6.3.2.1 paragraph 4
1817
1818 if(
1819 op.id() == ID_address_of && op.get_bool(ID_C_implicit) &&
1820 to_address_of_expr(op).object().type().id() == ID_code)
1821 {
1822 // make the implicit address_of an explicit address_of
1823 exprt tmp;
1824 tmp.swap(op);
1825 tmp.set(ID_C_implicit, false);
1826 expr.swap(tmp);
1827 return;
1828 }
1829
1830 if(op.id()==ID_struct ||
1831 op.id()==ID_union ||
1832 op.id()==ID_array ||
1833 op.id()==ID_string_constant)
1834 {
1835 // these are really objects
1836 }
1837 else if(op.get_bool(ID_C_lvalue))
1838 {
1839 // ok
1840 }
1841 else if(op.type().id()==ID_code)
1842 {
1843 // ok
1844 }
1845 else
1846 {
1848 error() << "address_of error: '" << to_string(op) << "' not an lvalue"
1849 << eom;
1850 throw 0;
1851 }
1852
1853 expr.type()=pointer_type(op.type());
1854}
1855
1857{
1858 exprt &op = to_unary_expr(expr).op();
1859
1860 const typet op_type = op.type();
1861
1862 if(op_type.id()==ID_array)
1863 {
1864 // *a is the same as a[0]
1865 expr.id(ID_index);
1866 expr.type() = to_array_type(op_type).element_type();
1868 CHECK_RETURN(expr.operands().size() == 2);
1869 }
1870 else if(op_type.id()==ID_pointer)
1871 {
1872 expr.type() = to_pointer_type(op_type).base_type();
1873
1874 if(
1875 expr.type().id() == ID_empty &&
1877 {
1879 error() << "dereferencing void pointer" << eom;
1880 throw 0;
1881 }
1882 }
1883 else
1884 {
1886 error() << "operand of unary * '" << to_string(op)
1887 << "' is not a pointer, but got '" << to_string(op_type) << "'"
1888 << eom;
1889 throw 0;
1890 }
1891
1892 expr.set(ID_C_lvalue, true);
1893
1894 // if you dereference a pointer pointing to
1895 // a function, you get a pointer again
1896 // allowing ******...*p
1897
1899}
1900
1902{
1903 if(expr.type().id()==ID_code)
1904 {
1905 address_of_exprt tmp(expr, pointer_type(expr.type()));
1906 tmp.set(ID_C_implicit, true);
1907 tmp.add_source_location()=expr.source_location();
1908 expr=tmp;
1909 }
1910}
1911
1913{
1914 const irep_idt &statement=expr.get_statement();
1915
1916 if(statement==ID_preincrement ||
1917 statement==ID_predecrement ||
1918 statement==ID_postincrement ||
1919 statement==ID_postdecrement)
1920 {
1921 const exprt &op0 = to_unary_expr(expr).op();
1922 const typet &type0=op0.type();
1923
1924 if(!op0.get_bool(ID_C_lvalue))
1925 {
1927 error() << "prefix operator error: '" << to_string(op0)
1928 << "' not an lvalue" << eom;
1929 throw 0;
1930 }
1931
1932 if(type0.get_bool(ID_C_constant))
1933 {
1935 error() << "'" << to_string(op0) << "' is constant" << eom;
1936 throw 0;
1937 }
1938
1939 if(type0.id() == ID_c_enum_tag)
1940 {
1942 if(enum_type.is_incomplete())
1943 {
1945 error() << "operator '" << statement << "' given incomplete type '"
1946 << to_string(type0) << "'" << eom;
1947 throw 0;
1948 }
1949
1950 // increment/decrement on underlying type
1951 to_unary_expr(expr).op() =
1952 typecast_exprt(op0, enum_type.underlying_type());
1953 expr.type() = enum_type.underlying_type();
1954 }
1955 else if(type0.id() == ID_c_bit_field)
1956 {
1957 // promote to underlying type
1958 typet underlying_type = to_c_bit_field_type(type0).underlying_type();
1960 to_unary_expr(expr).op() = typecast_exprt(op0, underlying_type);
1961 expr.type()=underlying_type;
1963 expr.swap(result);
1964 }
1965 else if(type0.id() == ID_bool || type0.id() == ID_c_bool)
1966 {
1968 expr.type() = op0.type();
1969 }
1970 else if(is_numeric_type(type0))
1971 {
1972 expr.type()=type0;
1973 }
1974 else if(type0.id() == ID_pointer)
1975 {
1977 expr.type() = to_unary_expr(expr).op().type();
1978 }
1979 else
1980 {
1982 error() << "operator '" << statement << "' not defined for type '"
1983 << to_string(type0) << "'" << eom;
1984 throw 0;
1985 }
1986 }
1987 else if(statement.starts_with("assign"))
1989 else if(statement==ID_function_call)
1992 else if(statement==ID_statement_expression)
1994 else if(statement==ID_gcc_conditional_expression)
1996 else
1997 {
1999 error() << "unknown side effect: " << statement << eom;
2000 throw 0;
2001 }
2002}
2003
2006{
2007 INVARIANT(
2008 expr.function().id() == ID_symbol &&
2009 to_symbol_expr(expr.function()).get_identifier() == CPROVER_PREFIX
2010 "typed_target",
2011 "expression must be a " CPROVER_PREFIX "typed_target function call");
2012
2013 auto &f_op = to_symbol_expr(expr.function());
2014
2015 if(expr.arguments().size() != 1)
2016 {
2018 "expected 1 argument for " CPROVER_PREFIX "typed_target, found " +
2019 std::to_string(expr.arguments().size()),
2020 expr.source_location()};
2021 }
2022
2023 auto arg0 = expr.arguments().front();
2024
2025 if(!is_assignable(arg0) || !arg0.get_bool(ID_C_lvalue))
2026 {
2028 "argument of " CPROVER_PREFIX "typed_target must be assignable",
2029 arg0.source_location()};
2030 }
2031
2032 const auto &size = size_of_expr(arg0.type(), *this);
2033 if(!size.has_value())
2034 {
2036 "sizeof not defined for argument of " CPROVER_PREFIX
2037 "typed_target of type " +
2038 to_string(arg0.type()),
2039 arg0.source_location()};
2040 }
2041
2042 // rewrite call to "assignable"
2043 f_op.set_identifier(CPROVER_PREFIX "assignable");
2044 exprt::operandst arguments;
2045 // pointer
2046 arguments.push_back(address_of_exprt(arg0));
2047 // size
2048 arguments.push_back(size.value());
2049 // is_pointer
2050 if(arg0.type().id() == ID_pointer)
2051 arguments.push_back(true_exprt());
2052 else
2053 arguments.push_back(false_exprt());
2054
2055 expr.arguments().swap(arguments);
2056 expr.type() = empty_typet();
2057}
2058
2061{
2062 INVARIANT(
2063 expr.function().id() == ID_symbol &&
2064 to_symbol_expr(expr.function()).get_identifier() == CPROVER_PREFIX
2065 "obeys_contract",
2066 "expression must be a " CPROVER_PREFIX "obeys_contract function call");
2067
2068 if(expr.arguments().size() != 2)
2069 {
2071 "expected 2 arguments for " CPROVER_PREFIX "obeys_contract, found " +
2072 std::to_string(expr.arguments().size()),
2073 expr.source_location()};
2074 }
2075
2076 // the first parameter must be a function pointer typed assignable path
2077 // expression, without side effects or ternary operator
2078 auto &function_pointer = expr.arguments()[0];
2079
2080 if(
2081 function_pointer.type().id() != ID_pointer ||
2082 to_pointer_type(function_pointer.type()).base_type().id() != ID_code ||
2083 !function_pointer.get_bool(ID_C_lvalue))
2084 {
2086 "the first argument of " CPROVER_PREFIX
2087 "obeys_contract must be a function pointer lvalue expression",
2088 function_pointer.source_location());
2089 }
2090
2092 {
2094 "the first argument of " CPROVER_PREFIX
2095 "obeys_contract must have no ternary operator",
2096 function_pointer.source_location());
2097 }
2098
2099 // second parameter must be the address of a function symbol
2100 auto &address_of_contract = expr.arguments()[1];
2101
2102 if(
2105 address_of_contract.type().id() != ID_pointer ||
2106 to_pointer_type(address_of_contract.type()).base_type().id() != ID_code)
2107 {
2109 "the second argument of " CPROVER_PREFIX
2110 "obeys_contract must must be a function symbol",
2111 address_of_contract.source_location());
2112 }
2113
2114 if(function_pointer.type() != address_of_contract.type())
2115 {
2117 "the first and second arguments of " CPROVER_PREFIX
2118 "obeys_contract must have the same function pointer type",
2119 expr.source_location());
2120 }
2121
2122 expr.type() = bool_typet();
2123}
2124
2126{
2127 return ::builtin_factory(
2128 identifier,
2129 config.ansi_c.float16_type,
2132}
2133
2136{
2137 if(expr.operands().size()!=2)
2138 {
2140 error() << "function_call side effect expects two operands" << eom;
2141 throw 0;
2142 }
2143
2144 exprt &f_op=expr.function();
2145
2146 // f_op is not yet typechecked, in contrast to the other arguments.
2147 // This is a big special case!
2148
2149 if(f_op.id()==ID_symbol)
2150 {
2151 irep_idt identifier=to_symbol_expr(f_op).get_identifier();
2152
2153 asm_label_mapt::const_iterator entry=
2154 asm_label_map.find(identifier);
2155 if(entry!=asm_label_map.end())
2156 identifier=entry->second;
2157
2158 if(symbol_table.symbols.find(identifier)==symbol_table.symbols.end())
2159 {
2160 // This is an undeclared function.
2161
2162 // Is it the polymorphic typed_target function ?
2163 if(identifier == CPROVER_PREFIX "typed_target")
2164 {
2166 }
2167 // Is this a builtin?
2168 else if(!builtin_factory(identifier))
2169 {
2170 // yes, it's a builtin
2171 }
2172 else if(
2173 identifier == "__noop" &&
2175 {
2176 // https://docs.microsoft.com/en-us/cpp/intrinsics/noop
2177 // typecheck and discard, just generating 0 instead
2178 for(auto &op : expr.arguments())
2179 typecheck_expr(op);
2180
2182 expr.swap(result);
2183
2184 return;
2185 }
2186 else if(
2187 identifier == "__builtin_nondeterministic_value" &&
2189 {
2190 // From Clang's documentation:
2191 // Each call to __builtin_nondeterministic_value returns a valid value
2192 // of the type given by the argument.
2193 // Clang only supports integer types, floating-point types, vector
2194 // types.
2195 if(expr.arguments().size() != 1)
2196 {
2197 error().source_location = f_op.source_location();
2198 error() << "__builtin_nondeterministic_value expects one operand"
2199 << eom;
2200 throw 0;
2201 }
2202 typecheck_expr(expr.arguments().front());
2203
2205 expr.arguments().front().type(), f_op.source_location()};
2206 expr.swap(result);
2207
2208 return;
2209 }
2210 else if(
2211 identifier == "__builtin_shuffle" &&
2213 {
2215 expr.swap(result);
2216
2217 return;
2218 }
2219 else if(identifier == "__builtin_shufflevector")
2220 {
2222 expr.swap(result);
2223
2224 return;
2225 }
2226 else if(
2227 identifier == CPROVER_PREFIX "saturating_minus" ||
2228 identifier == CPROVER_PREFIX "saturating_plus" ||
2229 identifier == "__builtin_elementwise_add_sat" ||
2230 identifier == "__builtin_elementwise_sub_sat")
2231 {
2233 expr.swap(result);
2234
2235 return;
2236 }
2237 else if(identifier == CPROVER_PREFIX "equal")
2238 {
2239 if(expr.arguments().size() != 2)
2240 {
2241 error().source_location = f_op.source_location();
2242 error() << "equal expects two operands" << eom;
2243 throw 0;
2244 }
2245
2247 expr.arguments().front(), expr.arguments().back());
2248 equality_expr.add_source_location() = expr.source_location();
2249
2250 if(equality_expr.lhs().type() != equality_expr.rhs().type())
2251 {
2252 error().source_location = f_op.source_location();
2253 error() << "equal expects two operands of same type" << eom;
2254 throw 0;
2255 }
2256
2257 expr.swap(equality_expr);
2258 return;
2259 }
2260 else if(
2261 identifier == CPROVER_PREFIX "overflow_minus" ||
2262 identifier == CPROVER_PREFIX "overflow_mult" ||
2263 identifier == CPROVER_PREFIX "overflow_plus" ||
2264 identifier == CPROVER_PREFIX "overflow_shl")
2265 {
2266 exprt overflow{identifier, typet{}, exprt::operandst{expr.arguments()}};
2267 overflow.add_source_location() = f_op.source_location();
2268
2269 if(identifier == CPROVER_PREFIX "overflow_minus")
2270 {
2271 overflow.id(ID_minus);
2273 }
2274 else if(identifier == CPROVER_PREFIX "overflow_mult")
2275 {
2276 overflow.id(ID_mult);
2278 }
2279 else if(identifier == CPROVER_PREFIX "overflow_plus")
2280 {
2281 overflow.id(ID_plus);
2283 }
2284 else if(identifier == CPROVER_PREFIX "overflow_shl")
2285 {
2286 overflow.id(ID_shl);
2288 }
2289
2291 overflow.operands()[0], overflow.id(), overflow.operands()[1]};
2292 of.add_source_location() = overflow.source_location();
2293 expr.swap(of);
2294 return;
2295 }
2296 else if(identifier == CPROVER_PREFIX "overflow_unary_minus")
2297 {
2299 tmp.add_source_location() = f_op.source_location();
2300
2302
2303 unary_minus_overflow_exprt overflow{tmp.operands().front()};
2304 overflow.add_source_location() = tmp.source_location();
2305 expr.swap(overflow);
2306 return;
2307 }
2308 else if(identifier == CPROVER_PREFIX "enum_is_in_range")
2309 {
2310 // Check correct number of arguments
2311 if(expr.arguments().size() != 1)
2312 {
2313 std::ostringstream error_message;
2314 error_message << identifier << " takes exactly 1 argument, but "
2315 << expr.arguments().size() << " were provided";
2317 error_message.str(), expr.source_location()};
2318 }
2319 const auto &arg1 = expr.arguments()[0];
2321 {
2322 // Can't enum range check a non-enum
2323 std::ostringstream error_message;
2324 error_message << identifier << " expects enum, but ("
2325 << expr2c(arg1, *this) << ") has type `"
2326 << type2c(arg1.type(), *this) << '`';
2328 error_message.str(), expr.source_location()};
2329 }
2330
2332 in_range.add_source_location() = expr.source_location();
2333 exprt lowered = in_range.lower(*this);
2334 expr.swap(lowered);
2335 return;
2336 }
2337 else if(
2338 identifier == CPROVER_PREFIX "r_ok" ||
2339 identifier == CPROVER_PREFIX "w_ok" ||
2340 identifier == CPROVER_PREFIX "rw_ok")
2341 {
2342 if(expr.arguments().size() != 1 && expr.arguments().size() != 2)
2343 {
2345 id2string(identifier) + " expects one or two operands",
2346 f_op.source_location()};
2347 }
2348
2349 // the first argument must be a pointer
2350 auto &pointer_expr = expr.arguments()[0];
2351 if(pointer_expr.type().id() == ID_array)
2352 {
2354 dest_type.base_type().set(ID_C_constant, true);
2355 implicit_typecast(pointer_expr, dest_type);
2356 }
2357 else if(pointer_expr.type().id() != ID_pointer)
2358 {
2360 id2string(identifier) + " expects a pointer as first argument",
2361 f_op.source_location()};
2362 }
2363
2364 // The second argument, when given, is a size_t.
2365 // When not given, use the pointer subtype.
2367
2368 if(expr.arguments().size() == 2)
2369 {
2371 size_expr = expr.arguments()[1];
2372 }
2373 else
2374 {
2375 // Won't do void *
2376 const auto &subtype =
2377 to_pointer_type(pointer_expr.type()).base_type();
2378 if(subtype.id() == ID_empty)
2379 {
2381 id2string(identifier) +
2382 " expects a size when given a void pointer",
2383 f_op.source_location()};
2384 }
2385
2386 auto size_expr_opt = size_of_expr(subtype, *this);
2387 CHECK_RETURN(size_expr_opt.has_value());
2388 size_expr = std::move(size_expr_opt.value());
2389 }
2390
2391 irep_idt id = identifier == CPROVER_PREFIX "r_ok" ? ID_r_ok
2392 : identifier == CPROVER_PREFIX "w_ok" ? ID_w_ok
2393 : ID_rw_ok;
2394
2395 r_or_w_ok_exprt ok_expr(id, pointer_expr, size_expr);
2396 ok_expr.add_source_location() = expr.source_location();
2397
2398 expr.swap(ok_expr);
2399 return;
2400 }
2401 else if(
2403 {
2405 shadow_memory_builtin->get_identifier();
2406
2407 const auto builtin_code_type =
2409
2410 INVARIANT(
2411 builtin_code_type.has_ellipsis() &&
2412 builtin_code_type.parameters().empty(),
2413 "Shadow memory builtins should be an ellipsis with 0 parameter");
2414
2415 // Add the symbol to the symbol table if it is not present yet.
2417 {
2418 symbolt new_symbol{
2420 new_symbol.base_name = shadow_memory_builtin_id;
2421 new_symbol.location = f_op.source_location();
2422 // Add an empty implementation to avoid warnings about missing
2423 // implementation later on
2424 new_symbol.value = code_blockt{};
2425
2426 symbol_table.add(new_symbol);
2427 }
2428
2429 // Swap the current `function` field with the newly generated
2430 // `shadow_memory_builtin` `symbol_exprt` and carry on with typechecking
2431 f_op = std::move(*shadow_memory_builtin);
2432 }
2433 else if(
2435 identifier, expr.arguments(), f_op.source_location()))
2436 {
2437 irep_idt identifier_with_type = gcc_polymorphic->get_identifier();
2438 auto &parameters = to_code_type(gcc_polymorphic->type()).parameters();
2439 INVARIANT(
2440 !parameters.empty(),
2441 "GCC polymorphic built-ins should have at least one parameter");
2442
2443 // For all atomic/sync polymorphic built-ins (which are the ones handled
2444 // by typecheck_gcc_polymorphic_builtin), looking at the first parameter
2445 // suffices to distinguish different implementations.
2446 if(parameters.front().type().id() == ID_pointer)
2447 {
2449 id2string(identifier) + "_" +
2451 to_pointer_type(parameters.front().type()).base_type(), *this);
2452 }
2453 else
2454 {
2456 id2string(identifier) + "_" +
2457 type_to_partial_identifier(parameters.front().type(), *this);
2458 }
2459 gcc_polymorphic->set_identifier(identifier_with_type);
2460
2462 {
2463 for(std::size_t i = 0; i < parameters.size(); ++i)
2464 {
2465 const std::string base_name = "p_" + std::to_string(i);
2466
2467 parameter_symbolt new_symbol;
2468
2469 new_symbol.name =
2470 id2string(identifier_with_type) + "::" + base_name;
2471 new_symbol.base_name = base_name;
2472 new_symbol.location = f_op.source_location();
2473 new_symbol.type = parameters[i].type();
2474 new_symbol.is_parameter = true;
2475 new_symbol.is_lvalue = true;
2476 new_symbol.mode = ID_C;
2477
2478 parameters[i].set_identifier(new_symbol.name);
2479 parameters[i].set_base_name(new_symbol.base_name);
2480
2481 symbol_table.add(new_symbol);
2482 }
2483
2484 symbolt new_symbol{
2486 new_symbol.base_name = identifier_with_type;
2487 new_symbol.location = f_op.source_location();
2488 code_blockt implementation =
2491 return_type = to_code_type(gcc_polymorphic->type()).return_type();
2492 typecheck_code(implementation);
2494 new_symbol.value = implementation;
2495
2496 symbol_table.add(new_symbol);
2497 }
2498
2499 f_op = std::move(*gcc_polymorphic);
2500 }
2501 else
2502 {
2503 // This is an undeclared function that's not a builtin.
2504 // Let's just add it.
2505 // We do a bit of return-type guessing, but just a bit.
2507
2508 // The following isn't really right and sound, but there
2509 // are too many idiots out there who use malloc and the like
2510 // without the right header file.
2511 if(identifier=="malloc" ||
2512 identifier=="realloc" ||
2513 identifier=="reallocf" ||
2514 identifier=="valloc")
2515 {
2517 }
2518
2519 symbolt new_symbol{
2520 identifier, code_typet({}, guessed_return_type), mode};
2521 new_symbol.base_name=identifier;
2522 new_symbol.location=expr.source_location();
2523 new_symbol.type.set(ID_C_incomplete, true);
2524
2525 // TODO: should also guess some argument types
2526
2528 move_symbol(new_symbol, symbol_ptr);
2529
2530 // We increase the verbosity level of the warning
2531 // for gcc/clang __builtin_ functions, since there are too many.
2532 if(identifier.starts_with("__builtin_"))
2533 {
2534 debug().source_location = f_op.find_source_location();
2535 debug() << "builtin '" << identifier << "' is unknown" << eom;
2536 }
2537 else
2538 {
2539 warning().source_location = f_op.find_source_location();
2540 warning() << "function '" << identifier << "' is not declared" << eom;
2541 }
2542 }
2543 }
2544 }
2545
2546 // typecheck it now
2548
2549 const typet f_op_type = f_op.type();
2550
2552 {
2553 const auto &mathematical_function_type =
2555
2556 // check number of arguments
2557 if(expr.arguments().size() != mathematical_function_type.domain().size())
2558 {
2559 error().source_location = f_op.source_location();
2560 error() << "expected " << mathematical_function_type.domain().size()
2561 << " arguments but got " << expr.arguments().size() << eom;
2562 throw 0;
2563 }
2564
2565 // check the types of the arguments
2566 for(auto &p :
2567 make_range(expr.arguments()).zip(mathematical_function_type.domain()))
2568 {
2569 if(p.first.type() != p.second)
2570 {
2571 error().source_location = p.first.source_location();
2572 error() << "expected argument of type " << to_string(p.second)
2573 << " but got " << to_string(p.first.type()) << eom;
2574 throw 0;
2575 }
2576 }
2577
2578 function_application_exprt function_application(f_op, expr.arguments());
2579
2580 function_application.add_source_location() = expr.source_location();
2581
2582 expr.swap(function_application);
2583 return;
2584 }
2585
2586 if(f_op_type.id()!=ID_pointer)
2587 {
2588 error().source_location = f_op.source_location();
2589 error() << "expected function/function pointer as argument but got '"
2590 << to_string(f_op_type) << "'" << eom;
2591 throw 0;
2592 }
2593
2594 // do implicit dereference
2595 if(f_op.id() == ID_address_of && f_op.get_bool(ID_C_implicit))
2596 {
2597 f_op = to_address_of_expr(f_op).object();
2598 }
2599 else
2600 {
2602 tmp.set(ID_C_implicit, true);
2603 tmp.add_source_location()=f_op.source_location();
2604 f_op.swap(tmp);
2605 }
2606
2607 if(f_op.type().id()!=ID_code)
2608 {
2609 error().source_location = f_op.source_location();
2610 error() << "expected code as argument" << eom;
2611 throw 0;
2612 }
2613
2614 const code_typet &code_type=to_code_type(f_op.type());
2615
2616 expr.type()=code_type.return_type();
2617
2619
2620 if(tmp.is_not_nil())
2621 expr.swap(tmp);
2622 else
2624}
2625
2628{
2629 const exprt &f_op=expr.function();
2630 const source_locationt &source_location=expr.source_location();
2631
2632 // some built-in functions
2633 if(f_op.id()!=ID_symbol)
2634 return nil_exprt();
2635
2636 const irep_idt &identifier=to_symbol_expr(f_op).get_identifier();
2637
2638 if(identifier == CPROVER_PREFIX "pointer_equals")
2639 {
2640 if(expr.arguments().size() != 2)
2641 {
2642 error().source_location = f_op.source_location();
2643 error() << CPROVER_PREFIX "pointer_equals expects two operands; "
2644 << expr.arguments().size() << "provided." << eom;
2645 throw 0;
2646 }
2648 return nil_exprt();
2649 }
2650 else if(identifier == CPROVER_PREFIX "is_fresh")
2651 {
2652 if(expr.arguments().size() != 2)
2653 {
2654 error().source_location = f_op.source_location();
2655 error() << CPROVER_PREFIX "is_fresh expects two operands; "
2656 << expr.arguments().size() << "provided." << eom;
2657 throw 0;
2658 }
2660 return nil_exprt();
2661 }
2662 else if(identifier == CPROVER_PREFIX "obeys_contract")
2663 {
2665 // returning nil leaves the call expression in place
2666 return nil_exprt();
2667 }
2668 else if(identifier == CPROVER_PREFIX "pointer_in_range_dfcc")
2669 {
2670 // same as pointer_in_range with experimental support for DFCC contracts
2671 // -- do not use
2672 if(expr.arguments().size() != 3)
2673 {
2675 CPROVER_PREFIX "pointer_in_range_dfcc expects three arguments",
2676 expr.source_location()};
2677 }
2678
2679 for(const auto &arg : expr.arguments())
2680 {
2681 if(arg.type().id() != ID_pointer)
2682 {
2685 "pointer_in_range_dfcc expects pointer-typed arguments",
2686 arg.source_location()};
2687 }
2688 }
2689 return nil_exprt();
2690 }
2691 else if(identifier == CPROVER_PREFIX "same_object")
2692 {
2693 if(expr.arguments().size()!=2)
2694 {
2695 error().source_location = f_op.source_location();
2696 error() << "same_object expects two operands" << eom;
2697 throw 0;
2698 }
2699
2701
2703 same_object(expr.arguments()[0], expr.arguments()[1]);
2704 same_object_expr.add_source_location()=source_location;
2705
2706 return same_object_expr;
2707 }
2708 else if(identifier==CPROVER_PREFIX "get_must")
2709 {
2710 if(expr.arguments().size()!=2)
2711 {
2712 error().source_location = f_op.source_location();
2713 error() << "get_must expects two operands" << eom;
2714 throw 0;
2715 }
2716
2718
2720 expr.arguments()[0], ID_get_must, expr.arguments()[1]);
2721 get_must_expr.add_source_location()=source_location;
2722
2723 return std::move(get_must_expr);
2724 }
2725 else if(identifier==CPROVER_PREFIX "get_may")
2726 {
2727 if(expr.arguments().size()!=2)
2728 {
2729 error().source_location = f_op.source_location();
2730 error() << "get_may expects two operands" << eom;
2731 throw 0;
2732 }
2733
2735
2737 expr.arguments()[0], ID_get_may, expr.arguments()[1]);
2738 get_may_expr.add_source_location()=source_location;
2739
2740 return std::move(get_may_expr);
2741 }
2742 else if(identifier == CPROVER_PREFIX "is_invalid_pointer")
2743 {
2744 if(expr.arguments().size()!=1)
2745 {
2746 error().source_location = f_op.source_location();
2747 error() << "is_invalid_pointer expects one operand" << eom;
2748 throw 0;
2749 }
2750
2752
2754 same_object_expr.add_source_location()=source_location;
2755
2756 return same_object_expr;
2757 }
2758 else if(identifier==CPROVER_PREFIX "buffer_size")
2759 {
2760 if(expr.arguments().size()!=1)
2761 {
2762 error().source_location = f_op.source_location();
2763 error() << "buffer_size expects one operand" << eom;
2764 throw 0;
2765 }
2766
2768
2769 exprt buffer_size_expr("buffer_size", size_type());
2770 buffer_size_expr.operands()=expr.arguments();
2771 buffer_size_expr.add_source_location()=source_location;
2772
2773 return buffer_size_expr;
2774 }
2775 else if(identifier == CPROVER_PREFIX "is_list")
2776 {
2777 // experimental feature for CHC encodings -- do not use
2778 if(expr.arguments().size() != 1)
2779 {
2780 error().source_location = f_op.source_location();
2781 error() << "is_list expects one operand" << eom;
2782 throw 0;
2783 }
2784
2786
2787 if(
2788 expr.arguments()[0].type().id() != ID_pointer ||
2789 to_pointer_type(expr.arguments()[0].type()).base_type().id() !=
2791 {
2792 error().source_location = expr.arguments()[0].source_location();
2793 error() << "is_list expects a struct-pointer operand" << eom;
2794 throw 0;
2795 }
2796
2797 predicate_exprt is_list_expr("is_list");
2798 is_list_expr.operands() = expr.arguments();
2799 is_list_expr.add_source_location() = source_location;
2800
2801 return std::move(is_list_expr);
2802 }
2803 else if(identifier == CPROVER_PREFIX "is_dll")
2804 {
2805 // experimental feature for CHC encodings -- do not use
2806 if(expr.arguments().size() != 1)
2807 {
2808 error().source_location = f_op.source_location();
2809 error() << "is_dll expects one operand" << eom;
2810 throw 0;
2811 }
2812
2814
2815 if(
2816 expr.arguments()[0].type().id() != ID_pointer ||
2817 to_pointer_type(expr.arguments()[0].type()).base_type().id() !=
2819 {
2820 error().source_location = expr.arguments()[0].source_location();
2821 error() << "is_dll expects a struct-pointer operand" << eom;
2822 throw 0;
2823 }
2824
2825 predicate_exprt is_dll_expr("is_dll");
2826 is_dll_expr.operands() = expr.arguments();
2827 is_dll_expr.add_source_location() = source_location;
2828
2829 return std::move(is_dll_expr);
2830 }
2831 else if(identifier == CPROVER_PREFIX "is_cyclic_dll")
2832 {
2833 // experimental feature for CHC encodings -- do not use
2834 if(expr.arguments().size() != 1)
2835 {
2836 error().source_location = f_op.source_location();
2837 error() << "is_cyclic_dll expects one operand" << eom;
2838 throw 0;
2839 }
2840
2842
2843 if(
2844 expr.arguments()[0].type().id() != ID_pointer ||
2845 to_pointer_type(expr.arguments()[0].type()).base_type().id() !=
2847 {
2848 error().source_location = expr.arguments()[0].source_location();
2849 error() << "is_cyclic_dll expects a struct-pointer operand" << eom;
2850 throw 0;
2851 }
2852
2853 predicate_exprt is_cyclic_dll_expr("is_cyclic_dll");
2854 is_cyclic_dll_expr.operands() = expr.arguments();
2855 is_cyclic_dll_expr.add_source_location() = source_location;
2856
2857 return std::move(is_cyclic_dll_expr);
2858 }
2859 else if(identifier == CPROVER_PREFIX "is_sentinel_dll")
2860 {
2861 // experimental feature for CHC encodings -- do not use
2862 if(expr.arguments().size() != 2 && expr.arguments().size() != 3)
2863 {
2864 error().source_location = f_op.source_location();
2865 error() << "is_sentinel_dll expects two or three operands" << eom;
2866 throw 0;
2867 }
2868
2870
2872 args_no_cast.reserve(expr.arguments().size());
2873 for(const auto &argument : expr.arguments())
2874 {
2876 if(
2877 args_no_cast.back().type().id() != ID_pointer ||
2878 to_pointer_type(args_no_cast.back().type()).base_type().id() !=
2880 {
2881 error().source_location = expr.arguments()[0].source_location();
2882 error() << "is_sentinel_dll_node expects struct-pointer operands"
2883 << eom;
2884 throw 0;
2885 }
2886 }
2887
2888 predicate_exprt is_sentinel_dll_expr("is_sentinel_dll");
2890 is_sentinel_dll_expr.add_source_location() = source_location;
2891
2892 return std::move(is_sentinel_dll_expr);
2893 }
2894 else if(identifier == CPROVER_PREFIX "is_cstring")
2895 {
2896 // experimental feature for CHC encodings -- do not use
2897 if(expr.arguments().size() != 1)
2898 {
2899 error().source_location = f_op.source_location();
2900 error() << "is_cstring expects one operand" << eom;
2901 throw 0;
2902 }
2903
2905
2906 if(expr.arguments()[0].type().id() != ID_pointer)
2907 {
2908 error().source_location = expr.arguments()[0].source_location();
2909 error() << "is_cstring expects a pointer operand" << eom;
2910 throw 0;
2911 }
2912
2914 is_cstring_expr.add_source_location() = source_location;
2915
2916 return std::move(is_cstring_expr);
2917 }
2918 else if(identifier == CPROVER_PREFIX "cstrlen")
2919 {
2920 // experimental feature for CHC encodings -- do not use
2921 if(expr.arguments().size() != 1)
2922 {
2923 error().source_location = f_op.source_location();
2924 error() << "cstrlen expects one operand" << eom;
2925 throw 0;
2926 }
2927
2929
2930 if(expr.arguments()[0].type().id() != ID_pointer)
2931 {
2932 error().source_location = expr.arguments()[0].source_location();
2933 error() << "cstrlen expects a pointer operand" << eom;
2934 throw 0;
2935 }
2936
2938 cstrlen_expr.add_source_location() = source_location;
2939
2940 return std::move(cstrlen_expr);
2941 }
2942 else if(identifier==CPROVER_PREFIX "is_zero_string")
2943 {
2944 if(expr.arguments().size()!=1)
2945 {
2946 error().source_location = f_op.source_location();
2947 error() << "is_zero_string expects one operand" << eom;
2948 throw 0;
2949 }
2950
2952
2954 "is_zero_string", expr.arguments()[0], c_bool_type());
2955 is_zero_string_expr.set(ID_C_lvalue, true); // make it an lvalue
2956 is_zero_string_expr.add_source_location()=source_location;
2957
2958 return std::move(is_zero_string_expr);
2959 }
2960 else if(identifier==CPROVER_PREFIX "zero_string_length")
2961 {
2962 if(expr.arguments().size()!=1)
2963 {
2964 error().source_location = f_op.source_location();
2965 error() << "zero_string_length expects one operand" << eom;
2966 throw 0;
2967 }
2968
2970
2971 exprt zero_string_length_expr("zero_string_length", size_type());
2972 zero_string_length_expr.operands()=expr.arguments();
2973 zero_string_length_expr.set(ID_C_lvalue, true); // make it an lvalue
2974 zero_string_length_expr.add_source_location()=source_location;
2975
2977 }
2978 else if(identifier==CPROVER_PREFIX "DYNAMIC_OBJECT")
2979 {
2980 if(expr.arguments().size()!=1)
2981 {
2982 error().source_location = f_op.source_location();
2983 error() << "dynamic_object expects one argument" << eom;
2984 throw 0;
2985 }
2986
2988
2990 is_dynamic_object_expr.add_source_location() = source_location;
2991
2993 }
2994 else if(identifier == CPROVER_PREFIX "LIVE_OBJECT")
2995 {
2996 if(expr.arguments().size() != 1)
2997 {
2998 error().source_location = f_op.source_location();
2999 error() << "live_object expects one argument" << eom;
3000 throw 0;
3001 }
3002
3004
3006 live_object_expr.add_source_location() = source_location;
3007
3008 return live_object_expr;
3009 }
3010 else if(identifier == CPROVER_PREFIX "pointer_in_range")
3011 {
3012 if(expr.arguments().size() != 3)
3013 {
3014 error().source_location = f_op.source_location();
3015 error() << "pointer_in_range expects three arguments" << eom;
3016 throw 0;
3017 }
3018
3020
3022 expr.arguments()[0], expr.arguments()[1], expr.arguments()[2]);
3023 pointer_in_range_expr.add_source_location() = source_location;
3024
3025 return pointer_in_range_expr;
3026 }
3027 else if(identifier == CPROVER_PREFIX "WRITEABLE_OBJECT")
3028 {
3029 if(expr.arguments().size() != 1)
3030 {
3031 error().source_location = f_op.source_location();
3032 error() << "writeable_object expects one argument" << eom;
3033 throw 0;
3034 }
3035
3037
3039 writeable_object_expr.add_source_location() = source_location;
3040
3041 return writeable_object_expr;
3042 }
3043 else if(identifier == CPROVER_PREFIX "separate")
3044 {
3045 // experimental feature for CHC encodings -- do not use
3046 if(expr.arguments().size() < 2)
3047 {
3048 error().source_location = f_op.source_location();
3049 error() << "separate expects two or more arguments" << eom;
3050 throw 0;
3051 }
3052
3054
3056 separate_expr.add_source_location() = source_location;
3057
3058 return separate_expr;
3059 }
3060 else if(identifier==CPROVER_PREFIX "POINTER_OFFSET")
3061 {
3062 if(expr.arguments().size()!=1)
3063 {
3064 error().source_location = f_op.source_location();
3065 error() << "pointer_offset expects one argument" << eom;
3066 throw 0;
3067 }
3068
3070
3072 pointer_offset_expr.add_source_location()=source_location;
3073
3075 }
3076 else if(identifier == CPROVER_PREFIX "OBJECT_SIZE")
3077 {
3078 if(expr.arguments().size() != 1)
3079 {
3080 error().source_location = f_op.source_location();
3081 error() << "object_size expects one operand" << eom;
3082 throw 0;
3083 }
3084
3086
3088 object_size_expr.add_source_location() = source_location;
3089
3090 return std::move(object_size_expr);
3091 }
3092 else if(identifier==CPROVER_PREFIX "POINTER_OBJECT")
3093 {
3094 if(expr.arguments().size()!=1)
3095 {
3096 error().source_location = f_op.source_location();
3097 error() << "pointer_object expects one argument" << eom;
3098 throw 0;
3099 }
3100
3102
3104 pointer_object_expr.add_source_location() = source_location;
3105
3107 }
3108 else if(identifier=="__builtin_bswap16" ||
3109 identifier=="__builtin_bswap32" ||
3110 identifier=="__builtin_bswap64")
3111 {
3112 if(expr.arguments().size()!=1)
3113 {
3114 error().source_location = f_op.source_location();
3115 error() << identifier << " expects one operand" << eom;
3116 throw 0;
3117 }
3118
3120
3121 // these are hard-wired to 8 bits according to the gcc manual
3122 bswap_exprt bswap_expr(expr.arguments().front(), 8, expr.type());
3123 bswap_expr.add_source_location()=source_location;
3124
3125 return std::move(bswap_expr);
3126 }
3127 else if(
3128 identifier == "__builtin_rotateleft8" ||
3129 identifier == "__builtin_rotateleft16" ||
3130 identifier == "__builtin_rotateleft32" ||
3131 identifier == "__builtin_rotateleft64" ||
3132 identifier == "__builtin_rotateright8" ||
3133 identifier == "__builtin_rotateright16" ||
3134 identifier == "__builtin_rotateright32" ||
3135 identifier == "__builtin_rotateright64")
3136 {
3137 // clang only
3138 if(expr.arguments().size() != 2)
3139 {
3140 error().source_location = f_op.source_location();
3141 error() << identifier << " expects two operands" << eom;
3142 throw 0;
3143 }
3144
3146
3147 irep_idt id = (identifier == "__builtin_rotateleft8" ||
3148 identifier == "__builtin_rotateleft16" ||
3149 identifier == "__builtin_rotateleft32" ||
3150 identifier == "__builtin_rotateleft64")
3151 ? ID_rol
3152 : ID_ror;
3153
3154 shift_exprt rotate_expr(expr.arguments()[0], id, expr.arguments()[1]);
3155 rotate_expr.add_source_location() = source_location;
3156
3157 return std::move(rotate_expr);
3158 }
3159 else if(identifier=="__builtin_nontemporal_load")
3160 {
3161 if(expr.arguments().size()!=1)
3162 {
3163 error().source_location = f_op.source_location();
3164 error() << identifier << " expects one operand" << eom;
3165 throw 0;
3166 }
3167
3169
3170 // these return the subtype of the argument
3171 exprt &ptr_arg=expr.arguments().front();
3172
3173 if(ptr_arg.type().id()!=ID_pointer)
3174 {
3175 error().source_location = f_op.source_location();
3176 error() << "__builtin_nontemporal_load takes pointer as argument" << eom;
3177 throw 0;
3178 }
3179
3180 expr.type() = to_pointer_type(expr.arguments().front().type()).base_type();
3181
3182 return expr;
3183 }
3184 else if(
3185 identifier == "__builtin_fpclassify" ||
3186 identifier == CPROVER_PREFIX "fpclassify")
3187 {
3188 if(expr.arguments().size() != 6)
3189 {
3190 error().source_location = f_op.source_location();
3191 error() << identifier << " expects six arguments" << eom;
3192 throw 0;
3193 }
3194
3196
3197 // This gets 5 integers followed by a float or double.
3198 // The five integers are the return values for the cases
3199 // FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL and FP_ZERO.
3200 // gcc expects this to be able to produce compile-time constants.
3201
3202 const exprt &fp_value = expr.arguments()[5];
3203
3204 if(fp_value.type().id() != ID_floatbv)
3205 {
3206 error().source_location = fp_value.source_location();
3207 error() << "non-floating-point argument for " << identifier << eom;
3208 throw 0;
3209 }
3210
3211 const auto &floatbv_type = to_floatbv_type(fp_value.type());
3212
3213 const exprt zero = ieee_floatt::zero(floatbv_type).to_expr();
3214
3215 const auto &arguments = expr.arguments();
3216
3217 return if_exprt(
3219 arguments[0],
3220 if_exprt(
3222 arguments[1],
3223 if_exprt(
3225 arguments[2],
3226 if_exprt(
3228 arguments[4],
3229 arguments[3])))); // subnormal
3230 }
3231 else if(identifier==CPROVER_PREFIX "isnanf" ||
3232 identifier==CPROVER_PREFIX "isnand" ||
3233 identifier==CPROVER_PREFIX "isnanld" ||
3234 identifier=="__builtin_isnan")
3235 {
3236 if(expr.arguments().size()!=1)
3237 {
3238 error().source_location = f_op.source_location();
3239 error() << "isnan expects one operand" << eom;
3240 throw 0;
3241 }
3242
3244
3245 isnan_exprt isnan_expr(expr.arguments().front());
3246 isnan_expr.add_source_location()=source_location;
3247
3249 }
3250 else if(identifier==CPROVER_PREFIX "isfinitef" ||
3251 identifier==CPROVER_PREFIX "isfinited" ||
3252 identifier==CPROVER_PREFIX "isfiniteld")
3253 {
3254 if(expr.arguments().size()!=1)
3255 {
3256 error().source_location = f_op.source_location();
3257 error() << "isfinite expects one operand" << eom;
3258 throw 0;
3259 }
3260
3262
3263 isfinite_exprt isfinite_expr(expr.arguments().front());
3264 isfinite_expr.add_source_location()=source_location;
3265
3267 }
3268 else if(
3269 identifier == CPROVER_PREFIX "inf" || identifier == "__builtin_inf" ||
3270 identifier == "__builtin_huge_val")
3271 {
3275 inf_expr.add_source_location()=source_location;
3276
3277 return std::move(inf_expr);
3278 }
3279 else if(
3280 identifier == CPROVER_PREFIX "inff" || identifier == "__builtin_inff" ||
3281 identifier == "__builtin_huge_valf")
3282 {
3286 inff_expr.add_source_location()=source_location;
3287
3288 return std::move(inff_expr);
3289 }
3290 else if(
3291 identifier == CPROVER_PREFIX "infl" || identifier == "__builtin_infl" ||
3292 identifier == "__builtin_huge_vall")
3293 {
3297 infl_expr.add_source_location()=source_location;
3298
3299 return std::move(infl_expr);
3300 }
3301 else if(
3302 identifier == CPROVER_PREFIX "round_to_integralf" ||
3303 identifier == CPROVER_PREFIX "round_to_integrald" ||
3304 identifier == CPROVER_PREFIX "round_to_integralld")
3305 {
3306 if(expr.arguments().size() != 2)
3307 {
3308 error().source_location = f_op.source_location();
3309 error() << identifier << " expects two arguments" << eom;
3310 throw 0;
3311 }
3312
3315 round_to_integral_expr.add_source_location() = source_location;
3316
3317 return std::move(round_to_integral_expr);
3318 }
3319 else if(
3320 identifier == CPROVER_PREFIX "abs" || identifier == CPROVER_PREFIX "labs" ||
3321 identifier == CPROVER_PREFIX "llabs" ||
3322 identifier == CPROVER_PREFIX "imaxabs" ||
3323 identifier == CPROVER_PREFIX "fabs" ||
3324 identifier == CPROVER_PREFIX "fabsf" ||
3325 identifier == CPROVER_PREFIX "fabsl")
3326 {
3327 if(expr.arguments().size()!=1)
3328 {
3329 error().source_location = f_op.source_location();
3330 error() << "abs-functions expect one operand" << eom;
3331 throw 0;
3332 }
3333
3335
3336 abs_exprt abs_expr(expr.arguments().front());
3337 abs_expr.add_source_location()=source_location;
3338
3339 return std::move(abs_expr);
3340 }
3341 else if(
3342 identifier == CPROVER_PREFIX "fmod" ||
3343 identifier == CPROVER_PREFIX "fmodf" ||
3344 identifier == CPROVER_PREFIX "fmodl")
3345 {
3346 if(expr.arguments().size() != 2)
3347 {
3348 error().source_location = f_op.source_location();
3349 error() << "fmod-functions expect two operands" << eom;
3350 throw 0;
3351 }
3352
3354
3355 // Note that the semantics differ from the
3356 // "floating point remainder" operation as defined by IEEE.
3357 // Note that these do not take a rounding mode.
3359 expr.arguments()[0], ID_floatbv_mod, expr.arguments()[1]);
3360
3361 fmod_expr.add_source_location() = source_location;
3362
3363 return std::move(fmod_expr);
3364 }
3365 else if(
3366 identifier == CPROVER_PREFIX "remainder" ||
3367 identifier == CPROVER_PREFIX "remainderf" ||
3368 identifier == CPROVER_PREFIX "remainderl")
3369 {
3370 if(expr.arguments().size() != 2)
3371 {
3372 error().source_location = f_op.source_location();
3373 error() << "remainder-functions expect two operands" << eom;
3374 throw 0;
3375 }
3376
3378
3379 // The semantics of these functions is meant to match the
3380 // "floating point remainder" operation as defined by IEEE.
3381 // Note that these do not take a rounding mode.
3383 expr.arguments()[0], ID_floatbv_rem, expr.arguments()[1]);
3384
3385 floatbv_rem_expr.add_source_location() = source_location;
3386
3387 return std::move(floatbv_rem_expr);
3388 }
3389 else if(identifier==CPROVER_PREFIX "allocate")
3390 {
3391 if(expr.arguments().size()!=2)
3392 {
3393 error().source_location = f_op.source_location();
3394 error() << "allocate expects two operands" << eom;
3395 throw 0;
3396 }
3397
3399
3400 side_effect_exprt malloc_expr(ID_allocate, expr.type(), source_location);
3401 malloc_expr.operands()=expr.arguments();
3402
3403 return std::move(malloc_expr);
3404 }
3405 else if(
3406 (identifier == CPROVER_PREFIX "old") ||
3407 (identifier == CPROVER_PREFIX "loop_entry"))
3408 {
3409 if(expr.arguments().size() != 1)
3410 {
3411 error().source_location = f_op.source_location();
3412 error() << identifier << " expects one operand" << eom;
3413 throw 0;
3414 }
3415
3416 const auto &param_id = expr.arguments().front().id();
3417 if(!(param_id == ID_dereference || param_id == ID_member ||
3420 param_id == ID_index))
3421 {
3422 error().source_location = f_op.source_location();
3423 error() << "Tracking history of " << param_id
3424 << " expressions is not supported yet." << eom;
3425 throw 0;
3426 }
3427
3428 irep_idt id = identifier == CPROVER_PREFIX "old" ? ID_old : ID_loop_entry;
3429
3430 history_exprt old_expr(expr.arguments()[0], id);
3431 old_expr.add_source_location() = source_location;
3432
3433 return std::move(old_expr);
3434 }
3435 else if(identifier==CPROVER_PREFIX "isinff" ||
3436 identifier==CPROVER_PREFIX "isinfd" ||
3437 identifier==CPROVER_PREFIX "isinfld" ||
3438 identifier=="__builtin_isinf")
3439 {
3440 if(expr.arguments().size()!=1)
3441 {
3442 error().source_location = f_op.source_location();
3443 error() << identifier << " expects one operand" << eom;
3444 throw 0;
3445 }
3446
3448
3449 const exprt &fp_value = expr.arguments().front();
3450
3451 if(fp_value.type().id() != ID_floatbv)
3452 {
3453 error().source_location = fp_value.source_location();
3454 error() << "non-floating-point argument for " << identifier << eom;
3455 throw 0;
3456 }
3457
3458 isinf_exprt isinf_expr(expr.arguments().front());
3459 isinf_expr.add_source_location()=source_location;
3460
3462 }
3463 else if(identifier == "__builtin_isinf_sign")
3464 {
3465 if(expr.arguments().size() != 1)
3466 {
3467 error().source_location = f_op.source_location();
3468 error() << identifier << " expects one operand" << eom;
3469 throw 0;
3470 }
3471
3473
3474 // returns 1 for +inf and -1 for -inf, and 0 otherwise
3475
3476 const exprt &fp_value = expr.arguments().front();
3477
3478 if(fp_value.type().id() != ID_floatbv)
3479 {
3480 error().source_location = fp_value.source_location();
3481 error() << "non-floating-point argument for " << identifier << eom;
3482 throw 0;
3483 }
3484
3486 isinf_expr.add_source_location() = source_location;
3487
3488 return if_exprt(
3490 if_exprt(
3492 from_integer(-1, expr.type()),
3493 from_integer(1, expr.type())),
3494 from_integer(0, expr.type()));
3495 }
3496 else if(identifier == CPROVER_PREFIX "isnormalf" ||
3497 identifier == CPROVER_PREFIX "isnormald" ||
3498 identifier == CPROVER_PREFIX "isnormalld" ||
3499 identifier == "__builtin_isnormal")
3500 {
3501 if(expr.arguments().size()!=1)
3502 {
3503 error().source_location = f_op.source_location();
3504 error() << identifier << " expects one operand" << eom;
3505 throw 0;
3506 }
3507
3509
3510 const exprt &fp_value = expr.arguments()[0];
3511
3512 if(fp_value.type().id() != ID_floatbv)
3513 {
3514 error().source_location = fp_value.source_location();
3515 error() << "non-floating-point argument for " << identifier << eom;
3516 throw 0;
3517 }
3518
3519 isnormal_exprt isnormal_expr(expr.arguments().front());
3520 isnormal_expr.add_source_location()=source_location;
3521
3523 }
3524 else if(identifier==CPROVER_PREFIX "signf" ||
3525 identifier==CPROVER_PREFIX "signd" ||
3526 identifier==CPROVER_PREFIX "signld" ||
3527 identifier=="__builtin_signbit" ||
3528 identifier=="__builtin_signbitf" ||
3529 identifier=="__builtin_signbitl")
3530 {
3531 if(expr.arguments().size()!=1)
3532 {
3533 error().source_location = f_op.source_location();
3534 error() << identifier << " expects one operand" << eom;
3535 throw 0;
3536 }
3537
3539
3540 sign_exprt sign_expr(expr.arguments().front());
3541 sign_expr.add_source_location()=source_location;
3542
3544 }
3545 else if(identifier=="__builtin_popcount" ||
3546 identifier=="__builtin_popcountl" ||
3547 identifier=="__builtin_popcountll" ||
3548 identifier=="__popcnt16" ||
3549 identifier=="__popcnt" ||
3550 identifier=="__popcnt64")
3551 {
3552 if(expr.arguments().size()!=1)
3553 {
3554 error().source_location = f_op.source_location();
3555 error() << identifier << " expects one operand" << eom;
3556 throw 0;
3557 }
3558
3560
3561 popcount_exprt popcount_expr(expr.arguments().front(), expr.type());
3562 popcount_expr.add_source_location()=source_location;
3563
3564 return std::move(popcount_expr);
3565 }
3566 else if(
3567 identifier == "__builtin_clz" || identifier == "__builtin_clzl" ||
3568 identifier == "__builtin_clzll" || identifier == "__lzcnt16" ||
3569 identifier == "__lzcnt" || identifier == "__lzcnt64")
3570 {
3571 if(expr.arguments().size() != 1)
3572 {
3573 error().source_location = f_op.source_location();
3574 error() << identifier << " expects one operand" << eom;
3575 throw 0;
3576 }
3577
3579
3581 expr.arguments().front(), identifier.starts_with("__lzcnt"), expr.type()};
3582 clz.add_source_location() = source_location;
3583
3584 return std::move(clz);
3585 }
3586 else if(
3587 identifier == "__builtin_ctz" || identifier == "__builtin_ctzl" ||
3588 identifier == "__builtin_ctzll")
3589 {
3590 if(expr.arguments().size() != 1)
3591 {
3592 error().source_location = f_op.source_location();
3593 error() << identifier << " expects one operand" << eom;
3594 throw 0;
3595 }
3596
3598
3600 expr.arguments().front(), false, expr.type()};
3601 ctz.add_source_location() = source_location;
3602
3603 return std::move(ctz);
3604 }
3605 else if(
3606 identifier == "__builtin_ffs" || identifier == "__builtin_ffsl" ||
3607 identifier == "__builtin_ffsll")
3608 {
3609 if(expr.arguments().size() != 1)
3610 {
3611 error().source_location = f_op.source_location();
3612 error() << identifier << " expects one operand" << eom;
3613 throw 0;
3614 }
3615
3617
3618 find_first_set_exprt ffs{expr.arguments().front(), expr.type()};
3619 ffs.add_source_location() = source_location;
3620
3621 return std::move(ffs);
3622 }
3623 else if(identifier=="__builtin_expect")
3624 {
3625 // This is a gcc extension to provide branch prediction.
3626 // We compile it away, but adding some IR instruction for
3627 // this would clearly be an option. Note that the type
3628 // of the return value is wired to "long", i.e.,
3629 // this may trigger a type conversion due to the signature
3630 // of this function.
3631 if(expr.arguments().size()!=2)
3632 {
3633 error().source_location = f_op.source_location();
3634 error() << "__builtin_expect expects two arguments" << eom;
3635 throw 0;
3636 }
3637
3639
3640 return typecast_exprt(expr.arguments()[0], expr.type());
3641 }
3642 else if(
3643 identifier == "__builtin_object_size" ||
3644 identifier == "__builtin_dynamic_object_size")
3645 {
3646 // These are gcc extensions to provide information about
3647 // object sizes at compile time
3648 // http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
3649 // Our behavior is as if it was never possible to determine the object that
3650 // the pointer pointed to.
3651
3652 if(expr.arguments().size()!=2)
3653 {
3654 error().source_location = f_op.source_location();
3655 error() << "__builtin_object_size expects two arguments" << eom;
3656 throw 0;
3657 }
3658
3660
3661 make_constant(expr.arguments()[1]);
3662
3664
3665 if(expr.arguments()[1] == true)
3666 arg1=1;
3667 else if(expr.arguments()[1] == false)
3668 arg1=0;
3669 else if(to_integer(to_constant_expr(expr.arguments()[1]), arg1))
3670 {
3671 error().source_location = f_op.source_location();
3672 error() << "__builtin_object_size expects constant as second argument, "
3673 << "but got " << to_string(expr.arguments()[1]) << eom;
3674 throw 0;
3675 }
3676
3677 exprt tmp;
3678
3679 // the following means "don't know"
3680 if(arg1==0 || arg1==1)
3681 {
3682 tmp=from_integer(-1, size_type());
3683 tmp.add_source_location()=f_op.source_location();
3684 }
3685 else
3686 {
3688 tmp.add_source_location()=f_op.source_location();
3689 }
3690
3691 return tmp;
3692 }
3693 else if(identifier=="__builtin_choose_expr")
3694 {
3695 // this is a gcc extension similar to ?:
3696 if(expr.arguments().size()!=3)
3697 {
3698 error().source_location = f_op.source_location();
3699 error() << "__builtin_choose_expr expects three arguments" << eom;
3700 throw 0;
3701 }
3702
3704
3705 exprt arg0 =
3708
3709 if(arg0 == true)
3710 return expr.arguments()[1];
3711 else
3712 return expr.arguments()[2];
3713 }
3714 else if(identifier=="__builtin_constant_p")
3715 {
3716 // this is a gcc extension to tell whether the argument
3717 // is known to be a compile-time constant
3718 if(expr.arguments().size()!=1)
3719 {
3720 error().source_location = f_op.source_location();
3721 error() << "__builtin_constant_p expects one argument" << eom;
3722 throw 0;
3723 }
3724
3725 // do not typecheck the argument - it is never evaluated, and thus side
3726 // effects must not show up either
3727
3728 // try to produce constant
3729 exprt tmp1=expr.arguments().front();
3730 simplify(tmp1, *this);
3731
3732 bool is_constant=false;
3733
3734 // Need to do some special treatment for string literals,
3735 // which are (void *)&("lit"[0])
3736 if(
3737 tmp1.id() == ID_typecast &&
3738 to_typecast_expr(tmp1).op().id() == ID_address_of &&
3739 to_address_of_expr(to_typecast_expr(tmp1).op()).object().id() ==
3740 ID_index &&
3742 .array()
3743 .id() == ID_string_constant)
3744 {
3745 is_constant=true;
3746 }
3747 else
3748 is_constant=tmp1.is_constant();
3749
3751 tmp2.add_source_location()=source_location;
3752
3753 return tmp2;
3754 }
3755 else if(identifier=="__builtin_classify_type")
3756 {
3757 // This is a gcc/clang extension that produces an integer
3758 // constant for the type of the argument expression.
3759 if(expr.arguments().size()!=1)
3760 {
3761 error().source_location = f_op.source_location();
3762 error() << "__builtin_classify_type expects one argument" << eom;
3763 throw 0;
3764 }
3765
3767
3768 exprt object=expr.arguments()[0];
3769
3770 // The value doesn't matter at all, we only care about the type.
3771 // Need to sync with typeclass.h.
3772 // use underlying type for bit fields
3773 const typet &type = object.type().id() == ID_c_bit_field
3774 ? to_c_bit_field_type(object.type()).underlying_type()
3775 : object.type();
3776
3777 unsigned type_number;
3778
3779 if(type.id() == ID_bool || type.id() == ID_c_bool)
3780 {
3781 // clang returns 4 for _Bool, gcc treats these as 'int'.
3782 type_number =
3784 }
3785 else
3786 {
3787 type_number = type.id() == ID_empty ? 0u
3788 : (type.id() == ID_bool || type.id() == ID_c_bool) ? 4u
3789 : (type.id() == ID_pointer || type.id() == ID_array) ? 5u
3790 : type.id() == ID_floatbv ? 8u
3791 : (type.id() == ID_complex &&
3792 to_complex_type(type).subtype().id() == ID_floatbv)
3793 ? 9u
3794 : type.id() == ID_struct_tag ? 12u
3795 : type.id() == ID_union_tag
3796 ? 13u
3797 : 1u; // int, short, char, enum_tag
3798 }
3799
3801 tmp.add_source_location()=source_location;
3802
3803 return tmp;
3804 }
3805 else if(
3806 identifier == "__builtin_add_overflow" ||
3807 identifier == "__builtin_sadd_overflow" ||
3808 identifier == "__builtin_saddl_overflow" ||
3809 identifier == "__builtin_saddll_overflow" ||
3810 identifier == "__builtin_uadd_overflow" ||
3811 identifier == "__builtin_uaddl_overflow" ||
3812 identifier == "__builtin_uaddll_overflow" ||
3813 identifier == "__builtin_add_overflow_p")
3814 {
3815 return typecheck_builtin_overflow(expr, ID_plus);
3816 }
3817 else if(
3818 identifier == "__builtin_sub_overflow" ||
3819 identifier == "__builtin_ssub_overflow" ||
3820 identifier == "__builtin_ssubl_overflow" ||
3821 identifier == "__builtin_ssubll_overflow" ||
3822 identifier == "__builtin_usub_overflow" ||
3823 identifier == "__builtin_usubl_overflow" ||
3824 identifier == "__builtin_usubll_overflow" ||
3825 identifier == "__builtin_sub_overflow_p")
3826 {
3828 }
3829 else if(
3830 identifier == "__builtin_mul_overflow" ||
3831 identifier == "__builtin_smul_overflow" ||
3832 identifier == "__builtin_smull_overflow" ||
3833 identifier == "__builtin_smulll_overflow" ||
3834 identifier == "__builtin_umul_overflow" ||
3835 identifier == "__builtin_umull_overflow" ||
3836 identifier == "__builtin_umulll_overflow" ||
3837 identifier == "__builtin_mul_overflow_p")
3838 {
3839 return typecheck_builtin_overflow(expr, ID_mult);
3840 }
3841 else if(
3842 identifier == "__builtin_bitreverse8" ||
3843 identifier == "__builtin_bitreverse16" ||
3844 identifier == "__builtin_bitreverse32" ||
3845 identifier == "__builtin_bitreverse64")
3846 {
3847 // clang only
3848 if(expr.arguments().size() != 1)
3849 {
3850 std::ostringstream error_message;
3851 error_message << "error: " << identifier << " expects one operand";
3853 error_message.str(), expr.source_location()};
3854 }
3855
3857
3859 bitreverse.add_source_location() = source_location;
3860
3861 return std::move(bitreverse);
3862 }
3863 else
3864 return nil_exprt();
3865 // NOLINTNEXTLINE(readability/fn_size)
3866}
3867
3870 const irep_idt &arith_op)
3871{
3872 const irep_idt &identifier = to_symbol_expr(expr.function()).get_identifier();
3873
3874 // check function signature
3875 if(expr.arguments().size() != 3)
3876 {
3877 std::ostringstream error_message;
3878 error_message << identifier << " takes exactly 3 arguments, but "
3879 << expr.arguments().size() << " were provided";
3881 error_message.str(), expr.source_location()};
3882 }
3883
3885
3886 auto lhs = expr.arguments()[0];
3887 auto rhs = expr.arguments()[1];
3888 auto result = expr.arguments()[2];
3889
3890 const bool is__p_variant = has_suffix(id2string(identifier), "_p");
3891
3892 {
3893 auto const raise_wrong_argument_error =
3894 [this, identifier](
3895 const exprt &wrong_argument, std::size_t argument_number, bool _p) {
3896 std::ostringstream error_message;
3897 error_message << "error: " << identifier << " has signature "
3898 << identifier << "(integral, integral, integral"
3899 << (_p ? "" : "*") << "), "
3900 << "but argument " << argument_number << " ("
3901 << expr2c(wrong_argument, *this) << ") has type `"
3902 << type2c(wrong_argument.type(), *this) << '`';
3904 error_message.str(), wrong_argument.source_location()};
3905 };
3906 for(int arg_index = 0; arg_index <= (!is__p_variant ? 1 : 2); ++arg_index)
3907 {
3908 auto const &argument = expr.arguments()[arg_index];
3909
3911 {
3913 }
3914 }
3915 if(
3916 !is__p_variant && (result.type().id() != ID_pointer ||
3918 to_pointer_type(result.type()).base_type())))
3919 {
3921 }
3922 }
3923
3925 std::move(lhs),
3926 std::move(rhs),
3927 std::move(result),
3928 expr.source_location()};
3929}
3930
3933{
3934 const irep_idt &identifier = to_symbol_expr(expr.function()).get_identifier();
3935
3936 // check function signature
3937 if(expr.arguments().size() != 2)
3938 {
3939 std::ostringstream error_message;
3940 error_message << "error: " << identifier
3941 << " takes exactly two arguments, but "
3942 << expr.arguments().size() << " were provided";
3944 error_message.str(), expr.source_location()};
3945 }
3946
3947 exprt result;
3948 if(
3949 identifier == CPROVER_PREFIX "saturating_minus" ||
3950 identifier == "__builtin_elementwise_sub_sat")
3951 {
3952 result = saturating_minus_exprt{expr.arguments()[0], expr.arguments()[1]};
3953 }
3954 else if(
3955 identifier == CPROVER_PREFIX "saturating_plus" ||
3956 identifier == "__builtin_elementwise_add_sat")
3957 {
3958 result = saturating_plus_exprt{expr.arguments()[0], expr.arguments()[1]};
3959 }
3960 else
3962
3964 result.add_source_location() = expr.source_location();
3965
3966 return result;
3967}
3968
3973{
3974 const exprt &f_op=expr.function();
3975 const code_typet &code_type=to_code_type(f_op.type());
3976 exprt::operandst &arguments=expr.arguments();
3977 const code_typet::parameterst &parameters = code_type.parameters();
3978
3979 // no. of arguments test
3980
3981 if(code_type.get_bool(ID_C_incomplete))
3982 {
3983 // can't check
3984 }
3985 else if(code_type.is_KnR())
3986 {
3987 // We are generous on KnR; any number is ok.
3988 // We will fill in missing ones with "nondet".
3989 for(std::size_t i = arguments.size(); i < parameters.size(); ++i)
3990 {
3991 arguments.push_back(
3992 side_effect_expr_nondett{parameters[i].type(), expr.source_location()});
3993 }
3994 }
3995 else if(code_type.has_ellipsis())
3996 {
3997 if(parameters.size() > arguments.size())
3998 {
4000 error() << "not enough function arguments" << eom;
4001 throw 0;
4002 }
4003 }
4004 else if(parameters.size() != arguments.size())
4005 {
4007 error() << "wrong number of function arguments: "
4008 << "expected " << parameters.size() << ", but got "
4009 << arguments.size() << eom;
4010 throw 0;
4011 }
4012
4013 for(std::size_t i=0; i<arguments.size(); i++)
4014 {
4015 exprt &op=arguments[i];
4016
4017 if(op.is_nil())
4018 {
4019 // ignore
4020 }
4021 else if(i < parameters.size())
4022 {
4023 const code_typet::parametert &parameter = parameters[i];
4024
4025 if(
4026 parameter.is_boolean() && op.id() == ID_side_effect &&
4027 op.get(ID_statement) == ID_assign && op.type().id() != ID_bool)
4028 {
4030 warning() << "assignment where Boolean argument is expected" << eom;
4031 }
4032
4033 implicit_typecast(op, parameter.type());
4034 }
4035 else
4036 {
4037 // don't know type, just do standard conversion
4038
4039 if(op.type().id() == ID_array)
4040 {
4042 dest_type.base_type().set(ID_C_constant, true);
4044 }
4045 }
4046 }
4047}
4048
4050{
4051 // nothing to do
4052}
4053
4055{
4056 exprt &operand = to_unary_expr(expr).op();
4057
4058 const typet &o_type = operand.type();
4059
4060 if(o_type.id()==ID_vector)
4061 {
4062 if(is_number(to_vector_type(o_type).element_type()))
4063 {
4064 // Vector arithmetic.
4065 expr.type()=operand.type();
4066 return;
4067 }
4068 }
4069
4071
4072 if(is_number(operand.type()))
4073 {
4074 expr.type()=operand.type();
4075 return;
4076 }
4077
4079 error() << "operator '" << expr.id() << "' not defined for type '"
4080 << to_string(operand.type()) << "'" << eom;
4081 throw 0;
4082}
4083
4085{
4087
4088 // This is not quite accurate: the standard says the result
4089 // should be of type 'int'.
4090 // We do 'bool' anyway to get more compact formulae. Eventually,
4091 // this should be achieved by means of simplification, and not
4092 // in the frontend.
4093 expr.type()=bool_typet();
4094}
4095
4097 const vector_typet &type0,
4098 const vector_typet &type1)
4099{
4100 // This is relatively restrictive!
4101
4102 // compare dimension
4103 const auto s0 = numeric_cast<mp_integer>(type0.size());
4104 const auto s1 = numeric_cast<mp_integer>(type1.size());
4105 if(!s0.has_value())
4106 return false;
4107 if(!s1.has_value())
4108 return false;
4109 if(*s0 != *s1)
4110 return false;
4111
4112 // compare subtype
4113 if(
4114 (type0.element_type().id() == ID_signedbv ||
4115 type0.element_type().id() == ID_unsignedbv) &&
4116 (type1.element_type().id() == ID_signedbv ||
4117 type1.element_type().id() == ID_unsignedbv) &&
4118 to_bitvector_type(type0.element_type()).get_width() ==
4119 to_bitvector_type(type1.element_type()).get_width())
4120 return true;
4121
4122 return type0.element_type() == type1.element_type();
4123}
4124
4126{
4127 auto &binary_expr = to_binary_expr(expr);
4128 exprt &op0 = binary_expr.op0();
4129 exprt &op1 = binary_expr.op1();
4130
4131 const typet o_type0 = op0.type();
4132 const typet o_type1 = op1.type();
4133
4134 if(o_type0.id()==ID_vector &&
4135 o_type1.id()==ID_vector)
4136 {
4137 if(
4140 is_number(to_vector_type(o_type0).element_type()))
4141 {
4142 // Vector arithmetic has fairly strict typing rules, no promotion
4143 op1 = typecast_exprt::conditional_cast(op1, op0.type());
4144 expr.type()=op0.type();
4145 return;
4146 }
4147 }
4148 else if(
4149 o_type0.id() == ID_vector && o_type1.id() != ID_vector &&
4151 {
4152 // convert op1 to the vector type
4153 op1 = typecast_exprt(op1, o_type0);
4154 expr.type() = o_type0;
4155 return;
4156 }
4157 else if(
4158 o_type0.id() != ID_vector && o_type1.id() == ID_vector &&
4160 {
4161 // convert op0 to the vector type
4162 op0 = typecast_exprt(op0, o_type1);
4163 expr.type() = o_type1;
4164 return;
4165 }
4166
4167 if(expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
4168 {
4170 }
4171 else
4172 {
4173 // promote!
4175 }
4176
4177 const typet &type0 = op0.type();
4178 const typet &type1 = op1.type();
4179
4180 if(expr.id()==ID_plus || expr.id()==ID_minus ||
4181 expr.id()==ID_mult || expr.id()==ID_div)
4182 {
4183 if(type0.id()==ID_pointer || type1.id()==ID_pointer)
4184 {
4186 return;
4187 }
4188 else if(type0==type1)
4189 {
4190 if(is_number(type0))
4191 {
4192 expr.type()=type0;
4193 return;
4194 }
4195 }
4196 }
4197 else if(expr.id()==ID_mod)
4198 {
4199 if(type0==type1)
4200 {
4201 if(type0.id()==ID_signedbv || type0.id()==ID_unsignedbv)
4202 {
4203 expr.type()=type0;
4204 return;
4205 }
4206 }
4207 }
4208 else if(
4209 expr.id() == ID_bitand || expr.id() == ID_bitnand ||
4210 expr.id() == ID_bitxor || expr.id() == ID_bitor)
4211 {
4212 if(type0==type1)
4213 {
4214 if(is_number(type0))
4215 {
4216 expr.type()=type0;
4217 return;
4218 }
4219 else if(type0.id()==ID_bool)
4220 {
4221 if(expr.id()==ID_bitand)
4222 expr.id(ID_and);
4223 else if(expr.id() == ID_bitnand)
4224 expr.id(ID_nand);
4225 else if(expr.id()==ID_bitor)
4226 expr.id(ID_or);
4227 else if(expr.id()==ID_bitxor)
4228 expr.id(ID_xor);
4229 else
4231 expr.type()=type0;
4232 return;
4233 }
4234 }
4235 }
4236 else if(expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
4237 {
4238 if(
4239 type0 == type1 &&
4240 (type0.id() == ID_signedbv || type0.id() == ID_unsignedbv))
4241 {
4242 expr.type() = type0;
4243 return;
4244 }
4245 }
4246
4248 error() << "operator '" << expr.id() << "' not defined for types '"
4249 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4250 << eom;
4251 throw 0;
4252}
4253
4255{
4256 PRECONDITION(expr.id() == ID_shl || expr.id() == ID_shr);
4257
4258 exprt &op0=expr.op0();
4259 exprt &op1=expr.op1();
4260
4261 const typet o_type0 = op0.type();
4262 const typet o_type1 = op1.type();
4263
4264 if(o_type0.id()==ID_vector &&
4265 o_type1.id()==ID_vector)
4266 {
4267 if(
4268 to_vector_type(o_type0).element_type() ==
4269 to_vector_type(o_type1).element_type() &&
4270 is_number(to_vector_type(o_type0).element_type()))
4271 {
4272 // {a0, a1, ..., an} >> {b0, b1, ..., bn} ==
4273 // {a0 >> b0, a1 >> b1, ..., an >> bn}
4274 // Fairly strict typing rules, no promotion
4275 expr.type()=op0.type();
4276 return;
4277 }
4278 }
4279
4280 if(
4281 o_type0.id() == ID_vector &&
4282 is_number(to_vector_type(o_type0).element_type()) && is_number(o_type1))
4283 {
4284 // {a0, a1, ..., an} >> b == {a0 >> b, a1 >> b, ..., an >> b}
4285 op1 = typecast_exprt(op1, o_type0);
4286 expr.type()=op0.type();
4287 return;
4288 }
4289
4290 // must do the promotions _separately_!
4293
4294 if(is_number(op0.type()) &&
4295 is_number(op1.type()))
4296 {
4297 expr.type()=op0.type();
4298
4299 if(expr.id()==ID_shr) // shifting operation depends on types
4300 {
4301 const typet &op0_type = op0.type();
4302
4303 if(op0_type.id()==ID_unsignedbv)
4304 {
4305 expr.id(ID_lshr);
4306 return;
4307 }
4308 else if(op0_type.id()==ID_signedbv)
4309 {
4310 expr.id(ID_ashr);
4311 return;
4312 }
4313 }
4314
4315 return;
4316 }
4317
4319 error() << "operator '" << expr.id() << "' not defined for types '"
4320 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4321 << eom;
4322 throw 0;
4323}
4324
4326{
4327 const typet &type=expr.type();
4328 PRECONDITION(type.id() == ID_pointer);
4329
4330 const typet &base_type = to_pointer_type(type).base_type();
4331
4332 if(
4333 base_type.id() == ID_struct_tag &&
4334 follow_tag(to_struct_tag_type(base_type)).is_incomplete())
4335 {
4337 error() << "pointer arithmetic with unknown object size" << eom;
4338 throw 0;
4339 }
4340 else if(
4341 base_type.id() == ID_union_tag &&
4342 follow_tag(to_union_tag_type(base_type)).is_incomplete())
4343 {
4345 error() << "pointer arithmetic with unknown object size" << eom;
4346 throw 0;
4347 }
4348 else if(
4349 base_type.id() == ID_empty &&
4351 {
4353 error() << "pointer arithmetic with unknown object size" << eom;
4354 throw 0;
4355 }
4356 else if(base_type.id() == ID_empty)
4357 {
4358 // This is a gcc extension.
4359 // https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.html
4361 expr.swap(tc);
4362 }
4363}
4364
4366{
4367 auto &binary_expr = to_binary_expr(expr);
4368 exprt &op0 = binary_expr.op0();
4369 exprt &op1 = binary_expr.op1();
4370
4371 const typet &type0 = op0.type();
4372 const typet &type1 = op1.type();
4373
4374 if(expr.id()==ID_minus ||
4375 (expr.id()==ID_side_effect && expr.get(ID_statement)==ID_assign_minus))
4376 {
4377 if(type0.id()==ID_pointer &&
4378 type1.id()==ID_pointer)
4379 {
4380 if(type0 != type1)
4381 {
4383 "pointer subtraction over different types", expr.source_location()};
4384 }
4385 expr.type()=pointer_diff_type();
4388 return;
4389 }
4390
4391 if(type0.id()==ID_pointer &&
4392 (type1.id()==ID_bool ||
4393 type1.id()==ID_c_bool ||
4394 type1.id()==ID_unsignedbv ||
4395 type1.id()==ID_signedbv ||
4396 type1.id()==ID_c_bit_field ||
4397 type1.id()==ID_c_enum_tag))
4398 {
4400 make_index_type(op1);
4401 expr.type() = op0.type();
4402 return;
4403 }
4404 }
4405 else if(expr.id()==ID_plus ||
4406 (expr.id()==ID_side_effect && expr.get(ID_statement)==ID_assign_plus))
4407 {
4408 exprt *p_op, *int_op;
4409
4410 if(type0.id()==ID_pointer)
4411 {
4412 p_op=&op0;
4413 int_op=&op1;
4414 }
4415 else if(type1.id()==ID_pointer)
4416 {
4417 p_op=&op1;
4418 int_op=&op0;
4419 }
4420 else
4421 {
4422 p_op=int_op=nullptr;
4424 }
4425
4426 const typet &int_op_type = int_op->type();
4427
4428 if(int_op_type.id()==ID_bool ||
4429 int_op_type.id()==ID_c_bool ||
4430 int_op_type.id()==ID_unsignedbv ||
4431 int_op_type.id()==ID_signedbv ||
4434 {
4437 expr.type()=p_op->type();
4438 return;
4439 }
4440 }
4441
4442 irep_idt op_name;
4443
4444 if(expr.id()==ID_side_effect)
4445 op_name=to_side_effect_expr(expr).get_statement();
4446 else
4447 op_name=expr.id();
4448
4450 error() << "operator '" << op_name << "' not defined for types '"
4451 << to_string(type0) << "' and '" << to_string(type1) << "'" << eom;
4452 throw 0;
4453}
4454
4456{
4457 auto &binary_expr = to_binary_expr(expr);
4460
4461 // This is not quite accurate: the standard says the result
4462 // should be of type 'int'.
4463 // We do 'bool' anyway to get more compact formulae. Eventually,
4464 // this should be achieved by means of simplification, and not
4465 // in the frontend.
4466 expr.type()=bool_typet();
4467}
4468
4470 side_effect_exprt &expr)
4471{
4472 const irep_idt &statement=expr.get_statement();
4473
4474 auto &binary_expr = to_binary_expr(expr);
4475 exprt &op0 = binary_expr.op0();
4476 exprt &op1 = binary_expr.op1();
4477
4478 {
4479 const typet &type0=op0.type();
4480
4481 if(type0.id()==ID_empty)
4482 {
4484 error() << "cannot assign void" << eom;
4485 throw 0;
4486 }
4487
4488 if(!op0.get_bool(ID_C_lvalue))
4489 {
4491 error() << "assignment error: '" << to_string(op0) << "' not an lvalue"
4492 << eom;
4493 throw 0;
4494 }
4495
4496 if(type0.get_bool(ID_C_constant))
4497 {
4499 error() << "'" << to_string(op0) << "' is constant" << eom;
4500 throw 0;
4501 }
4502
4503 // refuse to assign arrays
4504 if(type0.id() == ID_array)
4505 {
4507 error() << "direct assignments to arrays not permitted" << eom;
4508 throw 0;
4509 }
4510 }
4511
4512 // Add a cast to the underlying type for bit fields.
4513 if(op0.type() != op1.type() && op0.type().id() == ID_c_bit_field)
4514 {
4515 op1 =
4516 typecast_exprt{op1, to_c_bit_field_type(op0.type()).underlying_type()};
4517 }
4518
4519 const typet o_type0=op0.type();
4520 const typet o_type1=op1.type();
4521
4522 expr.type()=o_type0;
4523
4524 if(statement==ID_assign)
4525 {
4527 return;
4528 }
4529 else if(statement==ID_assign_shl ||
4530 statement==ID_assign_shr)
4531 {
4532 if(o_type0.id() == ID_vector)
4533 {
4535
4536 if(
4537 o_type1.id() == ID_vector &&
4538 vector_o_type0.element_type() ==
4539 to_vector_type(o_type1).element_type() &&
4540 is_number(vector_o_type0.element_type()))
4541 {
4542 return;
4543 }
4544 else if(is_number(vector_o_type0.element_type()) && is_number(o_type1))
4545 {
4546 op1 = typecast_exprt(op1, o_type0);
4547 return;
4548 }
4549 }
4550
4553
4554 if(is_number(op0.type()) && is_number(op1.type()))
4555 {
4556 if(statement==ID_assign_shl)
4557 {
4558 return;
4559 }
4560 else // assign_shr
4561 {
4562 // distinguish arithmetic from logical shifts by looking at type
4563
4564 typet underlying_type=op0.type();
4565
4566 if(underlying_type.id()==ID_unsignedbv ||
4567 underlying_type.id()==ID_c_bool)
4568 {
4570 return;
4571 }
4572 else if(underlying_type.id()==ID_signedbv)
4573 {
4575 return;
4576 }
4577 }
4578 }
4579 }
4580 else if(statement==ID_assign_bitxor ||
4581 statement==ID_assign_bitand ||
4582 statement==ID_assign_bitor)
4583 {
4584 // these are more restrictive
4585 if(o_type0.id()==ID_bool ||
4586 o_type0.id()==ID_c_bool)
4587 {
4589 if(
4590 op1.is_boolean() || op1.type().id() == ID_c_bool ||
4591 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4592 op1.type().id() == ID_signedbv || op1.type().id() == ID_c_bit_field)
4593 {
4594 return;
4595 }
4596 }
4597 else if(o_type0.id()==ID_c_enum_tag ||
4598 o_type0.id()==ID_unsignedbv ||
4599 o_type0.id()==ID_signedbv ||
4600 o_type0.id()==ID_c_bit_field)
4601 {
4603 if(
4604 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4605 op1.type().id() == ID_signedbv || op1.type().id() == ID_c_bit_field)
4606 {
4607 return;
4608 }
4609 }
4610 else if(o_type0.id()==ID_vector &&
4611 o_type1.id()==ID_vector)
4612 {
4613 // We are willing to do a modest amount of conversion
4616 {
4618 return;
4619 }
4620 }
4621 else if(
4622 o_type0.id() == ID_vector &&
4623 (o_type1.id() == ID_bool || o_type1.id() == ID_c_bool ||
4624 o_type1.id() == ID_c_enum_tag || o_type1.id() == ID_unsignedbv ||
4625 o_type1.id() == ID_signedbv))
4626 {
4628 op1 = typecast_exprt(op1, o_type0);
4629 return;
4630 }
4631 }
4632 else
4633 {
4634 if(o_type0.id()==ID_pointer &&
4635 (statement==ID_assign_minus || statement==ID_assign_plus))
4636 {
4638 return;
4639 }
4640 else if(o_type0.id()==ID_vector &&
4641 o_type1.id()==ID_vector)
4642 {
4643 // We are willing to do a modest amount of conversion
4646 {
4648 return;
4649 }
4650 }
4651 else if(o_type0.id() == ID_vector)
4652 {
4654
4655 if(
4656 is_number(op1.type()) || op1.is_boolean() ||
4657 op1.type().id() == ID_c_bool || op1.type().id() == ID_c_enum_tag)
4658 {
4659 op1 = typecast_exprt(op1, o_type0);
4660 return;
4661 }
4662 }
4663 else if(o_type0.id()==ID_bool ||
4664 o_type0.id()==ID_c_bool)
4665 {
4667 if(
4668 op1.is_boolean() || op1.type().id() == ID_c_bool ||
4669 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4670 op1.type().id() == ID_signedbv)
4671 {
4672 return;
4673 }
4674 }
4675 else
4676 {
4678
4679 if(
4680 is_number(op1.type()) || op1.is_boolean() ||
4681 op1.type().id() == ID_c_bool || op1.type().id() == ID_c_enum_tag)
4682 {
4683 return;
4684 }
4685 }
4686 }
4687
4689 error() << "assignment '" << statement << "' not defined for types '"
4690 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4691 << eom;
4692
4693 throw 0;
4694}
4695
4700{
4701public:
4703 {
4704 }
4705
4707 bool operator()(const exprt &e) const
4708 {
4709 return is_constant(e);
4710 }
4711
4712protected:
4714
4717 bool is_constant(const exprt &e) const
4718 {
4719 if(e.id() == ID_infinity)
4720 return true;
4721
4722 if(e.is_constant())
4723 return true;
4724
4725 if(e.id() == ID_address_of)
4726 {
4727 return is_constant_address_of(to_address_of_expr(e).object());
4728 }
4729 else if(
4730 e.id() == ID_typecast || e.id() == ID_array_of || e.id() == ID_plus ||
4731 e.id() == ID_mult || e.id() == ID_array || e.id() == ID_with ||
4732 e.id() == ID_struct || e.id() == ID_union || e.id() == ID_empty_union ||
4733 e.id() == ID_equal || e.id() == ID_notequal || e.id() == ID_lt ||
4734 e.id() == ID_le || e.id() == ID_gt || e.id() == ID_ge ||
4735 e.id() == ID_if || e.id() == ID_not || e.id() == ID_and ||
4736 e.id() == ID_or || e.id() == ID_bitnot || e.id() == ID_bitand ||
4737 e.id() == ID_bitor || e.id() == ID_bitxor || e.id() == ID_vector)
4738 {
4739 return std::all_of(
4740 e.operands().begin(), e.operands().end(), [this](const exprt &op) {
4741 return is_constant(op);
4742 });
4743 }
4744
4745 return false;
4746 }
4747
4749 bool is_constant_address_of(const exprt &e) const
4750 {
4751 if(e.id() == ID_symbol)
4752 {
4753 return e.type().id() == ID_code ||
4754 ns.lookup(to_symbol_expr(e).get_identifier()).is_static_lifetime;
4755 }
4756 else if(e.id() == ID_array && e.get_bool(ID_C_string_constant))
4757 return true;
4758 else if(e.id() == ID_label)
4759 return true;
4760 else if(e.id() == ID_index)
4761 {
4763
4764 return is_constant_address_of(index_expr.array()) &&
4765 is_constant(index_expr.index());
4766 }
4767 else if(e.id() == ID_member)
4768 {
4769 return is_constant_address_of(to_member_expr(e).compound());
4770 }
4771 else if(e.id() == ID_dereference)
4772 {
4774
4775 return is_constant(deref.pointer());
4776 }
4777 else if(e.id() == ID_string_constant)
4778 return true;
4779
4780 return false;
4781 }
4782};
4783
4785{
4786 source_locationt location = expr.find_source_location();
4787
4788 // Floating-point expressions may require a rounding mode.
4789 // ISO 9899:1999 F.7.2 says that the default is "round to nearest".
4790 // Some compilers have command-line options to override.
4791 const auto rounding_mode =
4793 adjust_float_expressions(expr, rounding_mode);
4794
4795 simplify(expr, *this);
4796 expr.add_source_location() = location;
4797
4798 if(!is_compile_time_constantt(*this)(expr))
4799 {
4800 error().source_location = location;
4801 error() << "expected constant expression, but got '" << to_string(expr)
4802 << "'" << eom;
4803 throw 0;
4804 }
4805}
4806
4808{
4809 source_locationt location = expr.find_source_location();
4810 make_constant(expr);
4811 make_index_type(expr);
4812 simplify(expr, *this);
4813 expr.add_source_location() = location;
4814
4815 if(!is_compile_time_constantt(*this)(expr))
4816 {
4817 error().source_location = location;
4818 error() << "conversion to integer constant failed" << eom;
4819 throw 0;
4820 }
4821}
4822
4824 const exprt &expr,
4825 const irep_idt &id,
4826 const std::string &message) const
4827{
4828 if(!has_subexpr(expr, id))
4829 return;
4830
4832 error() << message << eom;
4833 throw 0;
4834}
void adjust_float_expressions(exprt &expr, const exprt &rounding_mode)
Replaces arithmetic operations and typecasts involving floating point numbers with their equivalent f...
Symbolic Execution.
bool has_component_rec(const typet &type, const irep_idt &component_name, const namespacet &ns)
exprt get_component_rec(const exprt &struct_union, const irep_idt &component_name, const namespacet &ns)
C Language Type Checking.
ANSI-CC Language Type Checking.
ansi_c_declarationt & to_ansi_c_declaration(exprt &expr)
configt config
Definition config.cpp:25
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.
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition as_const.h:14
API to expression classes for bitvectors.
const shift_exprt & to_shift_expr(const exprt &expr)
Cast an exprt to a shift_exprt.
bool is_signed_or_unsigned_bitvector(const typet &type)
This method tests, if the given typet is a signed or unsigned bitvector.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_typet.
API to expression classes that are internal to the C frontend.
ANSI-C Language Type Checking.
already_typechecked_exprt & to_already_typechecked_expr(exprt &expr)
unsignedbv_typet unsigned_int_type()
Definition c_types.cpp:36
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
bitvector_typet char_type()
Definition c_types.cpp:106
floatbv_typet long_double_type()
Definition c_types.cpp:193
typet c_bool_type()
Definition c_types.cpp:100
bitvector_typet c_index_type()
Definition c_types.cpp:16
const c_bit_field_typet & to_c_bit_field_type(const typet &type)
Cast a typet to a c_bit_field_typet.
Definition c_types.h:80
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
Definition c_types.h:335
const c_enum_tag_typet & to_c_enum_tag_type(const typet &type)
Cast a typet to a c_enum_tag_typet.
Definition c_types.h:377
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
Absolute value.
Definition std_expr.h:442
Operator to return the address of an object.
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
const declaratorst & declarators() const
A base class for binary expressions.
Definition std_expr.h:638
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
A Boolean expression returning true, iff operation kind would result in an overflow when applied to o...
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition std_expr.h:731
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:762
Reverse the order of bits in a bit-vector.
The Boolean type.
Definition std_types.h:36
The byte swap expression.
Type for C bit fields These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (...
Definition c_types.h:20
The type of C enums.
Definition c_types.h:239
static std::optional< std::string > check_address_can_be_taken(const typet &)
virtual void typecheck_obeys_contract_call(side_effect_expr_function_callt &expr)
Checks an obeys_contract predicate occurrence.
virtual void typecheck_expr_main(exprt &expr)
symbol_table_baset & symbol_table
virtual void implicit_typecast(exprt &expr, const typet &type)
virtual void typecheck_expr_alignof(exprt &expr)
static bool is_numeric_type(const typet &src)
virtual void typecheck_expr_pointer_arithmetic(exprt &expr)
virtual void typecheck_expr_rel_vector(binary_exprt &expr)
virtual void typecheck_expr_address_of(exprt &expr)
virtual void make_index_type(exprt &expr)
std::map< irep_idt, source_locationt > labels_used
virtual void typecheck_expr_constant(exprt &expr)
virtual void typecheck_expr(exprt &expr)
virtual void do_initializer(exprt &initializer, const typet &type, bool force_constant)
virtual void typecheck_code(codet &code)
virtual void typecheck_expr_binary_arithmetic(exprt &expr)
virtual void adjust_float_rel(binary_relation_exprt &)
virtual void typecheck_expr_unary_arithmetic(exprt &expr)
virtual void typecheck_expr_sizeof(exprt &expr)
void move_symbol(symbolt &symbol, symbolt *&new_symbol)
virtual void typecheck_expr_side_effect(side_effect_exprt &expr)
void disallow_subexpr_by_id(const exprt &, const irep_idt &, const std::string &) const
bool gcc_vector_types_compatible(const vector_typet &, const vector_typet &)
virtual bool gcc_types_compatible_p(const typet &, const typet &)
virtual void typecheck_expr_index(exprt &expr)
virtual void typecheck_expr_function_identifier(exprt &expr)
virtual void typecheck_expr_shifts(shift_exprt &expr)
virtual void make_constant(exprt &expr)
virtual void typecheck_expr_comma(exprt &expr)
exprt typecheck_saturating_arithmetic(const side_effect_expr_function_callt &expr)
virtual void typecheck_expr_builtin_va_arg(exprt &expr)
virtual void implicit_typecast_arithmetic(exprt &expr)
virtual void typecheck_side_effect_function_call(side_effect_expr_function_callt &expr)
static void add_rounding_mode(exprt &)
std::list< codet > clean_code
virtual std::string to_string(const exprt &expr)
virtual void typecheck_expr_binary_boolean(exprt &expr)
void typecheck_declaration(ansi_c_declarationt &)
virtual void typecheck_side_effect_statement_expression(side_effect_exprt &expr)
virtual exprt do_special_functions(side_effect_expr_function_callt &expr)
asm_label_mapt asm_label_map
virtual std::optional< symbol_exprt > typecheck_shadow_memory_builtin(const side_effect_expr_function_callt &expr)
Typecheck the function if it is a shadow_memory builtin and return a symbol for it.
virtual void typecheck_expr_cw_va_arg_typeof(exprt &expr)
exprt typecheck_builtin_overflow(side_effect_expr_function_callt &expr, const irep_idt &arith_op)
virtual void typecheck_side_effect_gcc_conditional_expression(side_effect_exprt &expr)
virtual void typecheck_side_effect_assignment(side_effect_exprt &expr)
virtual code_blockt instantiate_gcc_polymorphic_builtin(const irep_idt &identifier, const symbol_exprt &function_symbol)
virtual void typecheck_expr_operands(exprt &expr)
virtual std::optional< symbol_exprt > typecheck_gcc_polymorphic_builtin(const irep_idt &identifier, const exprt::operandst &arguments, const source_locationt &source_location)
virtual void typecheck_typed_target_call(side_effect_expr_function_callt &expr)
const irep_idt const irep_idt mode
virtual void make_constant_index(exprt &expr)
virtual void typecheck_function_call_arguments(side_effect_expr_function_callt &expr)
Typecheck the parameters in a function call expression, and where necessary, make implicit casts arou...
virtual bool is_complete_type(const typet &type) const
id_type_mapt parameter_map
virtual void typecheck_expr_symbol(exprt &expr)
virtual void typecheck_expr_trinary(if_exprt &expr)
virtual void typecheck_expr_ptrmember(exprt &expr)
virtual void typecheck_arithmetic_pointer(exprt &expr)
virtual void typecheck_expr_unary_boolean(exprt &expr)
virtual void implicit_typecast_bool(exprt &expr)
virtual exprt typecheck_shuffle_vector(const side_effect_expr_function_callt &expr)
virtual void typecheck_expr_member(exprt &expr)
virtual void typecheck_expr_dereference(exprt &expr)
virtual void typecheck_type(typet &type)
virtual void typecheck_expr_typecast(exprt &expr)
virtual void typecheck_expr_rel(binary_relation_exprt &expr)
virtual void typecheck_expr_builtin_offsetof(exprt &expr)
virtual bool builtin_factory(const irep_idt &)
A codet representing sequential composition of program statements.
Definition std_code.h:130
static code_blockt from_list(const std::list< codet > &_list)
Definition std_code.h:148
A codet representing the declaration of a local variable.
Definition std_code.h:347
Base type of functions.
Definition std_types.h:583
std::vector< parametert > parameterst
Definition std_types.h:586
Data structure for representing an arbitrary statement in a program.
exprt & op0()
Definition expr.h:134
const irep_idt & get_statement() const
Imaginary part of the expression describing a complex number.
Definition std_expr.h:2027
Real part of the expression describing a complex number.
Definition std_expr.h:1984
Complex numbers made of pair of given subtype.
Definition std_types.h:1133
struct configt::ansi_ct ansi_c
A constant literal expression.
Definition std_expr.h:3126
The count leading zeros (counting the number of zero bits starting from the most-significant bit) exp...
The count trailing zeros (counting the number of zero bits starting from the least-significant bit) e...
An expression, akin to ISO C's strlen, that denotes the length of a zero-terminated string that start...
Operator to dereference a pointer.
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
The empty type.
Definition std_types.h:51
A Boolean expression returning true, iff the value of an enum-typed symbol equals one of the enum's d...
Definition c_expr.h:327
Equality.
Definition std_expr.h:1366
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
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition expr.h:229
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:213
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:3254
Returns one plus the index of the least-significant one bit, or zero if the operand is zero.
Round a floating-point number to an integral value considering the given rounding mode.
Fixed-width bit-vector with IEEE floating-point interpretation.
Application of (mathematical) function.
A class for an expression that indicates a history variable.
Definition c_expr.h:206
IEEE-floating-point equality.
static ieee_float_spect single_precision()
Definition ieee_float.h:70
static ieee_float_spect double_precision()
Definition ieee_float.h:76
static ieee_float_valuet zero(const floatbv_typet &type)
Definition ieee_float.h:172
static ieee_float_valuet plus_infinity(const ieee_float_spect &_spec)
Definition ieee_float.h:202
The trinary if-then-else operator.
Definition std_expr.h:2510
Array index operator.
Definition std_expr.h:1470
An expression denoting infinity.
Definition std_expr.h:3279
Thrown when we can't handle something in an input source file.
bool get_bool(const irep_idt &name) const
Definition irep.cpp:57
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition irep.cpp:482
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
subt & get_sub()
Definition irep.h:448
void swap(irept &irep)
Definition irep.h:434
const irep_idt & id() const
Definition irep.h:388
irept & add(const irep_idt &name)
Definition irep.cpp:103
bool is_nil() const
Definition irep.h:368
Architecturally similar to can_forward_propagatet, but specialized for what is a constexpr,...
is_compile_time_constantt(const namespacet &ns)
bool is_constant(const exprt &e) const
This function determines what expressions are to be propagated as "constants".
bool is_constant_address_of(const exprt &e) const
this function determines which reference-typed expressions are constant
bool operator()(const exprt &e) const
returns true iff the expression can be considered constant
A predicate that indicates that a zero-terminated string starts at the given address.
Evaluates to true if the operand is a pointer to a dynamic object.
Evaluates to true if the operand is finite.
Evaluates to true if the operand is infinite.
Evaluates to true if the operand is NaN.
Evaluates to true if the operand is a normal number.
A predicate that indicates that the object pointed to is live.
A type for mathematical functions (do not confuse with functions/methods in code)
source_locationt source_location
Definition message.h:239
mstreamt & error() const
Definition message.h:391
mstreamt & debug() const
Definition message.h:421
message_handlert & get_message_handler()
Definition message.h:183
mstreamt & warning() const
Definition message.h:396
mstreamt & result() const
Definition message.h:401
static eomt eom
Definition message.h:289
Binary multiplication Associativity is not specified.
Definition std_expr.h:1107
void follow_macros(exprt &) const
Follow macros to their values in a given expression.
Definition namespace.cpp:93
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
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The NIL expression.
Definition std_expr.h:3263
The null pointer constant.
Expression for finding the size (in bytes) of the object a pointer points to.
Symbol table entry of function parameterThis is a symbol generated as part of type checking.
Definition symbol.h:179
The plus expression Associativity is not specified.
Definition std_expr.h:1002
pointer_in_range(a, b, c) evaluates to true iff same_object(a, b, c) ∧ r_ok(a, offset(c)-offset(a)) ∧...
The popcount (counting the number of bits set to 1) expression.
A base class for expressions that are predicates, i.e., Boolean-typed.
Definition std_expr.h:574
A base class for a predicate that indicates that an address range is ok to read or write or both.
Saturating subtraction expression.
The saturating plus expression.
A predicate that indicates that the objects pointed to are distinct.
A base class for shift and rotate operators.
A side_effect_exprt representation of a function call side effect.
Definition std_code.h:1692
exprt::operandst & arguments()
Definition std_code.h:1718
A side_effect_exprt that returns a non-deterministically chosen value.
Definition std_code.h:1520
A Boolean expression returning true, iff the result of performing operation kind on operands a and b ...
Definition c_expr.h:118
An expression containing a side effect.
Definition std_code.h:1450
const irep_idt & get_statement() const
Definition std_code.h:1472
Sign of an expression Predicate is true if _op is negative, false otherwise.
Definition std_expr.h:596
Fixed-width bit-vector with two's complement interpretation.
const irep_idt & get_function() const
Base type for structs and unions.
Definition std_types.h:62
Expression to hold a symbol (variable)
Definition std_expr.h:131
virtual std::pair< symbolt &, bool > insert(symbolt symbol)=0
Move or copy a new symbol to the symbol table.
const symbolst & symbols
Read-only field, used to look up symbols given their names.
bool has_symbol(const irep_idt &name) const
Check whether a symbol exists in the symbol table.
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
Symbol table entry.
Definition symbol.h:28
bool is_extern
Definition symbol.h:74
bool is_macro
Definition symbol.h:62
bool is_static_lifetime
Definition symbol.h:70
bool is_parameter
Definition symbol.h:76
bool is_type
Definition symbol.h:61
source_locationt location
Source code location of definition of symbol.
Definition symbol.h:37
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
irep_idt irep_idt base_name
Name of module the symbol belongs to.
Definition symbol.h:46
const irep_idt & display_name() const
Return language specific display name if present.
Definition symbol.h:55
bool is_lvalue
Definition symbol.h:72
irep_idt mode
Language mode.
Definition symbol.h:49
The Boolean constant true.
Definition std_expr.h:3245
Type with multiple subtypes.
Definition type.h:222
Semantic type conversion.
Definition std_expr.h:2073
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2081
The type of an expression, extends irept.
Definition type.h:29
Generic base class for unary expressions.
Definition std_expr.h:361
A Boolean expression returning true, iff negation would result in an overflow when applied to the (si...
Union constructor from single element.
Definition std_expr.h:1770
The vector type.
Definition std_types.h:1064
A predicate that indicates that the object pointed to is writeable.
#define CPROVER_PREFIX
std::string expr2c(const exprt &expr, const namespacet &ns, const expr2c_configurationt &configuration)
Definition expr2c.cpp:4188
std::string type2c(const typet &type, const namespacet &ns, const expr2c_configurationt &configuration)
Definition expr2c.cpp:4204
#define Forall_operands(it, expr)
Definition expr.h:28
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
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
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
Deprecated expression utility functions.
API to expression classes for floating-point arithmetic.
const ieee_float_op_exprt & to_ieee_float_op_expr(const exprt &expr)
Cast an exprt to an ieee_float_op_exprt.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
API to expression classes for 'mathematical' expressions.
bool is_number(const typet &type)
Returns true if the type is a rational, real, integer, natural, complex, unsignedbv,...
Mathematical types.
const mathematical_function_typet & to_mathematical_function_type(const typet &type)
Cast a typet to a mathematical_function_typet.
mp_integer alignment(const typet &type, const namespacet &ns)
Definition padding.cpp:23
ANSI-C Language Type Checking.
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.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
std::optional< mp_integer > pointer_offset_bits(const typet &type, const namespacet &ns)
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
std::optional< exprt > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
Pointer Logic.
exprt pointer_offset(const exprt &pointer)
exprt same_object(const exprt &p1, const exprt &p2)
exprt pointer_object(const exprt &p)
Various predicates over pointers in programs.
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
exprt deref_expr(const exprt &expr)
Wraps a given expression into a dereference_exprt unless it is an address_of_exprt in which case it j...
bool simplify(exprt &expr, const namespacet &ns)
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
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition std_code.h:1506
side_effect_expr_statement_expressiont & to_side_effect_expr_statement_expression(exprt &expr)
Definition std_code.h:1669
side_effect_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
Definition std_code.h:1739
bool can_cast_expr< side_effect_expr_function_callt >(const exprt &base)
Definition std_code.h:1730
const code_blockt & to_code_block(const codet &code)
Definition std_code.h:203
bool can_cast_expr< side_effect_exprt >(const exprt &base)
Definition std_code.h:1498
const code_frontend_declt & to_code_frontend_decl(const codet &code)
Definition std_code.h:429
const codet & to_code(const exprt &expr)
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition std_expr.cpp:291
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition std_expr.h:895
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:715
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:426
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2590
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3072
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3197
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition std_types.h:1116
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
Definition std_types.h:29
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition std_types.h:1158
const struct_or_union_tag_typet & to_struct_or_union_tag_type(const typet &type)
Cast a typet to a struct_or_union_tag_typet.
Definition std_types.h:478
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
bool has_suffix(const std::string &s, const std::string &suffix)
Definition suffix.h:17
Author: Diffblue Ltd.
std::string type_to_partial_identifier(const typet &type, const namespacet &ns)
Constructs a string describing the given type, which can be used as part of a C identifier.
Type Naming for C.
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition type.h:208
#define size_type
Definition unistd.c:186