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(identifier==CPROVER_PREFIX "inf" ||
3269 identifier=="__builtin_inf")
3270 {
3274 inf_expr.add_source_location()=source_location;
3275
3276 return std::move(inf_expr);
3277 }
3278 else if(identifier==CPROVER_PREFIX "inff")
3279 {
3283 inff_expr.add_source_location()=source_location;
3284
3285 return std::move(inff_expr);
3286 }
3287 else if(identifier==CPROVER_PREFIX "infl")
3288 {
3292 infl_expr.add_source_location()=source_location;
3293
3294 return std::move(infl_expr);
3295 }
3296 else if(
3297 identifier == CPROVER_PREFIX "round_to_integralf" ||
3298 identifier == CPROVER_PREFIX "round_to_integrald" ||
3299 identifier == CPROVER_PREFIX "round_to_integralld")
3300 {
3301 if(expr.arguments().size() != 2)
3302 {
3303 error().source_location = f_op.source_location();
3304 error() << identifier << " expects two arguments" << eom;
3305 throw 0;
3306 }
3307
3310 round_to_integral_expr.add_source_location() = source_location;
3311
3312 return std::move(round_to_integral_expr);
3313 }
3314 else if(
3315 identifier == CPROVER_PREFIX "abs" || identifier == CPROVER_PREFIX "labs" ||
3316 identifier == CPROVER_PREFIX "llabs" ||
3317 identifier == CPROVER_PREFIX "imaxabs" ||
3318 identifier == CPROVER_PREFIX "fabs" ||
3319 identifier == CPROVER_PREFIX "fabsf" ||
3320 identifier == CPROVER_PREFIX "fabsl")
3321 {
3322 if(expr.arguments().size()!=1)
3323 {
3324 error().source_location = f_op.source_location();
3325 error() << "abs-functions expect one operand" << eom;
3326 throw 0;
3327 }
3328
3330
3331 abs_exprt abs_expr(expr.arguments().front());
3332 abs_expr.add_source_location()=source_location;
3333
3334 return std::move(abs_expr);
3335 }
3336 else if(
3337 identifier == CPROVER_PREFIX "fmod" ||
3338 identifier == CPROVER_PREFIX "fmodf" ||
3339 identifier == CPROVER_PREFIX "fmodl")
3340 {
3341 if(expr.arguments().size() != 2)
3342 {
3343 error().source_location = f_op.source_location();
3344 error() << "fmod-functions expect two operands" << eom;
3345 throw 0;
3346 }
3347
3349
3350 // Note that the semantics differ from the
3351 // "floating point remainder" operation as defined by IEEE.
3352 // Note that these do not take a rounding mode.
3354 expr.arguments()[0], ID_floatbv_mod, expr.arguments()[1]);
3355
3356 fmod_expr.add_source_location() = source_location;
3357
3358 return std::move(fmod_expr);
3359 }
3360 else if(
3361 identifier == CPROVER_PREFIX "remainder" ||
3362 identifier == CPROVER_PREFIX "remainderf" ||
3363 identifier == CPROVER_PREFIX "remainderl")
3364 {
3365 if(expr.arguments().size() != 2)
3366 {
3367 error().source_location = f_op.source_location();
3368 error() << "remainder-functions expect two operands" << eom;
3369 throw 0;
3370 }
3371
3373
3374 // The semantics of these functions is meant to match the
3375 // "floating point remainder" operation as defined by IEEE.
3376 // Note that these do not take a rounding mode.
3378 expr.arguments()[0], ID_floatbv_rem, expr.arguments()[1]);
3379
3380 floatbv_rem_expr.add_source_location() = source_location;
3381
3382 return std::move(floatbv_rem_expr);
3383 }
3384 else if(identifier==CPROVER_PREFIX "allocate")
3385 {
3386 if(expr.arguments().size()!=2)
3387 {
3388 error().source_location = f_op.source_location();
3389 error() << "allocate expects two operands" << eom;
3390 throw 0;
3391 }
3392
3394
3395 side_effect_exprt malloc_expr(ID_allocate, expr.type(), source_location);
3396 malloc_expr.operands()=expr.arguments();
3397
3398 return std::move(malloc_expr);
3399 }
3400 else if(
3401 (identifier == CPROVER_PREFIX "old") ||
3402 (identifier == CPROVER_PREFIX "loop_entry"))
3403 {
3404 if(expr.arguments().size() != 1)
3405 {
3406 error().source_location = f_op.source_location();
3407 error() << identifier << " expects one operand" << eom;
3408 throw 0;
3409 }
3410
3411 const auto &param_id = expr.arguments().front().id();
3412 if(!(param_id == ID_dereference || param_id == ID_member ||
3415 param_id == ID_index))
3416 {
3417 error().source_location = f_op.source_location();
3418 error() << "Tracking history of " << param_id
3419 << " expressions is not supported yet." << eom;
3420 throw 0;
3421 }
3422
3423 irep_idt id = identifier == CPROVER_PREFIX "old" ? ID_old : ID_loop_entry;
3424
3425 history_exprt old_expr(expr.arguments()[0], id);
3426 old_expr.add_source_location() = source_location;
3427
3428 return std::move(old_expr);
3429 }
3430 else if(identifier==CPROVER_PREFIX "isinff" ||
3431 identifier==CPROVER_PREFIX "isinfd" ||
3432 identifier==CPROVER_PREFIX "isinfld" ||
3433 identifier=="__builtin_isinf")
3434 {
3435 if(expr.arguments().size()!=1)
3436 {
3437 error().source_location = f_op.source_location();
3438 error() << identifier << " expects one operand" << eom;
3439 throw 0;
3440 }
3441
3443
3444 const exprt &fp_value = expr.arguments().front();
3445
3446 if(fp_value.type().id() != ID_floatbv)
3447 {
3448 error().source_location = fp_value.source_location();
3449 error() << "non-floating-point argument for " << identifier << eom;
3450 throw 0;
3451 }
3452
3453 isinf_exprt isinf_expr(expr.arguments().front());
3454 isinf_expr.add_source_location()=source_location;
3455
3457 }
3458 else if(identifier == "__builtin_isinf_sign")
3459 {
3460 if(expr.arguments().size() != 1)
3461 {
3462 error().source_location = f_op.source_location();
3463 error() << identifier << " expects one operand" << eom;
3464 throw 0;
3465 }
3466
3468
3469 // returns 1 for +inf and -1 for -inf, and 0 otherwise
3470
3471 const exprt &fp_value = expr.arguments().front();
3472
3473 if(fp_value.type().id() != ID_floatbv)
3474 {
3475 error().source_location = fp_value.source_location();
3476 error() << "non-floating-point argument for " << identifier << eom;
3477 throw 0;
3478 }
3479
3481 isinf_expr.add_source_location() = source_location;
3482
3483 return if_exprt(
3485 if_exprt(
3487 from_integer(-1, expr.type()),
3488 from_integer(1, expr.type())),
3489 from_integer(0, expr.type()));
3490 }
3491 else if(identifier == CPROVER_PREFIX "isnormalf" ||
3492 identifier == CPROVER_PREFIX "isnormald" ||
3493 identifier == CPROVER_PREFIX "isnormalld" ||
3494 identifier == "__builtin_isnormal")
3495 {
3496 if(expr.arguments().size()!=1)
3497 {
3498 error().source_location = f_op.source_location();
3499 error() << identifier << " expects one operand" << eom;
3500 throw 0;
3501 }
3502
3504
3505 const exprt &fp_value = expr.arguments()[0];
3506
3507 if(fp_value.type().id() != ID_floatbv)
3508 {
3509 error().source_location = fp_value.source_location();
3510 error() << "non-floating-point argument for " << identifier << eom;
3511 throw 0;
3512 }
3513
3514 isnormal_exprt isnormal_expr(expr.arguments().front());
3515 isnormal_expr.add_source_location()=source_location;
3516
3518 }
3519 else if(identifier==CPROVER_PREFIX "signf" ||
3520 identifier==CPROVER_PREFIX "signd" ||
3521 identifier==CPROVER_PREFIX "signld" ||
3522 identifier=="__builtin_signbit" ||
3523 identifier=="__builtin_signbitf" ||
3524 identifier=="__builtin_signbitl")
3525 {
3526 if(expr.arguments().size()!=1)
3527 {
3528 error().source_location = f_op.source_location();
3529 error() << identifier << " expects one operand" << eom;
3530 throw 0;
3531 }
3532
3534
3535 sign_exprt sign_expr(expr.arguments().front());
3536 sign_expr.add_source_location()=source_location;
3537
3539 }
3540 else if(identifier=="__builtin_popcount" ||
3541 identifier=="__builtin_popcountl" ||
3542 identifier=="__builtin_popcountll" ||
3543 identifier=="__popcnt16" ||
3544 identifier=="__popcnt" ||
3545 identifier=="__popcnt64")
3546 {
3547 if(expr.arguments().size()!=1)
3548 {
3549 error().source_location = f_op.source_location();
3550 error() << identifier << " expects one operand" << eom;
3551 throw 0;
3552 }
3553
3555
3556 popcount_exprt popcount_expr(expr.arguments().front(), expr.type());
3557 popcount_expr.add_source_location()=source_location;
3558
3559 return std::move(popcount_expr);
3560 }
3561 else if(
3562 identifier == "__builtin_clz" || identifier == "__builtin_clzl" ||
3563 identifier == "__builtin_clzll" || identifier == "__lzcnt16" ||
3564 identifier == "__lzcnt" || identifier == "__lzcnt64")
3565 {
3566 if(expr.arguments().size() != 1)
3567 {
3568 error().source_location = f_op.source_location();
3569 error() << identifier << " expects one operand" << eom;
3570 throw 0;
3571 }
3572
3574
3576 expr.arguments().front(), identifier.starts_with("__lzcnt"), expr.type()};
3577 clz.add_source_location() = source_location;
3578
3579 return std::move(clz);
3580 }
3581 else if(
3582 identifier == "__builtin_ctz" || identifier == "__builtin_ctzl" ||
3583 identifier == "__builtin_ctzll")
3584 {
3585 if(expr.arguments().size() != 1)
3586 {
3587 error().source_location = f_op.source_location();
3588 error() << identifier << " expects one operand" << eom;
3589 throw 0;
3590 }
3591
3593
3595 expr.arguments().front(), false, expr.type()};
3596 ctz.add_source_location() = source_location;
3597
3598 return std::move(ctz);
3599 }
3600 else if(
3601 identifier == "__builtin_ffs" || identifier == "__builtin_ffsl" ||
3602 identifier == "__builtin_ffsll")
3603 {
3604 if(expr.arguments().size() != 1)
3605 {
3606 error().source_location = f_op.source_location();
3607 error() << identifier << " expects one operand" << eom;
3608 throw 0;
3609 }
3610
3612
3613 find_first_set_exprt ffs{expr.arguments().front(), expr.type()};
3614 ffs.add_source_location() = source_location;
3615
3616 return std::move(ffs);
3617 }
3618 else if(identifier=="__builtin_expect")
3619 {
3620 // This is a gcc extension to provide branch prediction.
3621 // We compile it away, but adding some IR instruction for
3622 // this would clearly be an option. Note that the type
3623 // of the return value is wired to "long", i.e.,
3624 // this may trigger a type conversion due to the signature
3625 // of this function.
3626 if(expr.arguments().size()!=2)
3627 {
3628 error().source_location = f_op.source_location();
3629 error() << "__builtin_expect expects two arguments" << eom;
3630 throw 0;
3631 }
3632
3634
3635 return typecast_exprt(expr.arguments()[0], expr.type());
3636 }
3637 else if(
3638 identifier == "__builtin_object_size" ||
3639 identifier == "__builtin_dynamic_object_size")
3640 {
3641 // These are gcc extensions to provide information about
3642 // object sizes at compile time
3643 // http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
3644 // Our behavior is as if it was never possible to determine the object that
3645 // the pointer pointed to.
3646
3647 if(expr.arguments().size()!=2)
3648 {
3649 error().source_location = f_op.source_location();
3650 error() << "__builtin_object_size expects two arguments" << eom;
3651 throw 0;
3652 }
3653
3655
3656 make_constant(expr.arguments()[1]);
3657
3659
3660 if(expr.arguments()[1] == true)
3661 arg1=1;
3662 else if(expr.arguments()[1] == false)
3663 arg1=0;
3664 else if(to_integer(to_constant_expr(expr.arguments()[1]), arg1))
3665 {
3666 error().source_location = f_op.source_location();
3667 error() << "__builtin_object_size expects constant as second argument, "
3668 << "but got " << to_string(expr.arguments()[1]) << eom;
3669 throw 0;
3670 }
3671
3672 exprt tmp;
3673
3674 // the following means "don't know"
3675 if(arg1==0 || arg1==1)
3676 {
3677 tmp=from_integer(-1, size_type());
3678 tmp.add_source_location()=f_op.source_location();
3679 }
3680 else
3681 {
3683 tmp.add_source_location()=f_op.source_location();
3684 }
3685
3686 return tmp;
3687 }
3688 else if(identifier=="__builtin_choose_expr")
3689 {
3690 // this is a gcc extension similar to ?:
3691 if(expr.arguments().size()!=3)
3692 {
3693 error().source_location = f_op.source_location();
3694 error() << "__builtin_choose_expr expects three arguments" << eom;
3695 throw 0;
3696 }
3697
3699
3700 exprt arg0 =
3703
3704 if(arg0 == true)
3705 return expr.arguments()[1];
3706 else
3707 return expr.arguments()[2];
3708 }
3709 else if(identifier=="__builtin_constant_p")
3710 {
3711 // this is a gcc extension to tell whether the argument
3712 // is known to be a compile-time constant
3713 if(expr.arguments().size()!=1)
3714 {
3715 error().source_location = f_op.source_location();
3716 error() << "__builtin_constant_p expects one argument" << eom;
3717 throw 0;
3718 }
3719
3720 // do not typecheck the argument - it is never evaluated, and thus side
3721 // effects must not show up either
3722
3723 // try to produce constant
3724 exprt tmp1=expr.arguments().front();
3725 simplify(tmp1, *this);
3726
3727 bool is_constant=false;
3728
3729 // Need to do some special treatment for string literals,
3730 // which are (void *)&("lit"[0])
3731 if(
3732 tmp1.id() == ID_typecast &&
3733 to_typecast_expr(tmp1).op().id() == ID_address_of &&
3734 to_address_of_expr(to_typecast_expr(tmp1).op()).object().id() ==
3735 ID_index &&
3737 .array()
3738 .id() == ID_string_constant)
3739 {
3740 is_constant=true;
3741 }
3742 else
3743 is_constant=tmp1.is_constant();
3744
3746 tmp2.add_source_location()=source_location;
3747
3748 return tmp2;
3749 }
3750 else if(identifier=="__builtin_classify_type")
3751 {
3752 // This is a gcc/clang extension that produces an integer
3753 // constant for the type of the argument expression.
3754 if(expr.arguments().size()!=1)
3755 {
3756 error().source_location = f_op.source_location();
3757 error() << "__builtin_classify_type expects one argument" << eom;
3758 throw 0;
3759 }
3760
3762
3763 exprt object=expr.arguments()[0];
3764
3765 // The value doesn't matter at all, we only care about the type.
3766 // Need to sync with typeclass.h.
3767 // use underlying type for bit fields
3768 const typet &type = object.type().id() == ID_c_bit_field
3769 ? to_c_bit_field_type(object.type()).underlying_type()
3770 : object.type();
3771
3772 unsigned type_number;
3773
3774 if(type.id() == ID_bool || type.id() == ID_c_bool)
3775 {
3776 // clang returns 4 for _Bool, gcc treats these as 'int'.
3777 type_number =
3779 }
3780 else
3781 {
3782 type_number = type.id() == ID_empty ? 0u
3783 : (type.id() == ID_bool || type.id() == ID_c_bool) ? 4u
3784 : (type.id() == ID_pointer || type.id() == ID_array) ? 5u
3785 : type.id() == ID_floatbv ? 8u
3786 : (type.id() == ID_complex &&
3787 to_complex_type(type).subtype().id() == ID_floatbv)
3788 ? 9u
3789 : type.id() == ID_struct_tag ? 12u
3790 : type.id() == ID_union_tag
3791 ? 13u
3792 : 1u; // int, short, char, enum_tag
3793 }
3794
3796 tmp.add_source_location()=source_location;
3797
3798 return tmp;
3799 }
3800 else if(
3801 identifier == "__builtin_add_overflow" ||
3802 identifier == "__builtin_sadd_overflow" ||
3803 identifier == "__builtin_saddl_overflow" ||
3804 identifier == "__builtin_saddll_overflow" ||
3805 identifier == "__builtin_uadd_overflow" ||
3806 identifier == "__builtin_uaddl_overflow" ||
3807 identifier == "__builtin_uaddll_overflow" ||
3808 identifier == "__builtin_add_overflow_p")
3809 {
3810 return typecheck_builtin_overflow(expr, ID_plus);
3811 }
3812 else if(
3813 identifier == "__builtin_sub_overflow" ||
3814 identifier == "__builtin_ssub_overflow" ||
3815 identifier == "__builtin_ssubl_overflow" ||
3816 identifier == "__builtin_ssubll_overflow" ||
3817 identifier == "__builtin_usub_overflow" ||
3818 identifier == "__builtin_usubl_overflow" ||
3819 identifier == "__builtin_usubll_overflow" ||
3820 identifier == "__builtin_sub_overflow_p")
3821 {
3823 }
3824 else if(
3825 identifier == "__builtin_mul_overflow" ||
3826 identifier == "__builtin_smul_overflow" ||
3827 identifier == "__builtin_smull_overflow" ||
3828 identifier == "__builtin_smulll_overflow" ||
3829 identifier == "__builtin_umul_overflow" ||
3830 identifier == "__builtin_umull_overflow" ||
3831 identifier == "__builtin_umulll_overflow" ||
3832 identifier == "__builtin_mul_overflow_p")
3833 {
3834 return typecheck_builtin_overflow(expr, ID_mult);
3835 }
3836 else if(
3837 identifier == "__builtin_bitreverse8" ||
3838 identifier == "__builtin_bitreverse16" ||
3839 identifier == "__builtin_bitreverse32" ||
3840 identifier == "__builtin_bitreverse64")
3841 {
3842 // clang only
3843 if(expr.arguments().size() != 1)
3844 {
3845 std::ostringstream error_message;
3846 error_message << "error: " << identifier << " expects one operand";
3848 error_message.str(), expr.source_location()};
3849 }
3850
3852
3854 bitreverse.add_source_location() = source_location;
3855
3856 return std::move(bitreverse);
3857 }
3858 else
3859 return nil_exprt();
3860 // NOLINTNEXTLINE(readability/fn_size)
3861}
3862
3865 const irep_idt &arith_op)
3866{
3867 const irep_idt &identifier = to_symbol_expr(expr.function()).get_identifier();
3868
3869 // check function signature
3870 if(expr.arguments().size() != 3)
3871 {
3872 std::ostringstream error_message;
3873 error_message << identifier << " takes exactly 3 arguments, but "
3874 << expr.arguments().size() << " were provided";
3876 error_message.str(), expr.source_location()};
3877 }
3878
3880
3881 auto lhs = expr.arguments()[0];
3882 auto rhs = expr.arguments()[1];
3883 auto result = expr.arguments()[2];
3884
3885 const bool is__p_variant = has_suffix(id2string(identifier), "_p");
3886
3887 {
3888 auto const raise_wrong_argument_error =
3889 [this, identifier](
3890 const exprt &wrong_argument, std::size_t argument_number, bool _p) {
3891 std::ostringstream error_message;
3892 error_message << "error: " << identifier << " has signature "
3893 << identifier << "(integral, integral, integral"
3894 << (_p ? "" : "*") << "), "
3895 << "but argument " << argument_number << " ("
3896 << expr2c(wrong_argument, *this) << ") has type `"
3897 << type2c(wrong_argument.type(), *this) << '`';
3899 error_message.str(), wrong_argument.source_location()};
3900 };
3901 for(int arg_index = 0; arg_index <= (!is__p_variant ? 1 : 2); ++arg_index)
3902 {
3903 auto const &argument = expr.arguments()[arg_index];
3904
3906 {
3908 }
3909 }
3910 if(
3911 !is__p_variant && (result.type().id() != ID_pointer ||
3913 to_pointer_type(result.type()).base_type())))
3914 {
3916 }
3917 }
3918
3920 std::move(lhs),
3921 std::move(rhs),
3922 std::move(result),
3923 expr.source_location()};
3924}
3925
3928{
3929 const irep_idt &identifier = to_symbol_expr(expr.function()).get_identifier();
3930
3931 // check function signature
3932 if(expr.arguments().size() != 2)
3933 {
3934 std::ostringstream error_message;
3935 error_message << "error: " << identifier
3936 << " takes exactly two arguments, but "
3937 << expr.arguments().size() << " were provided";
3939 error_message.str(), expr.source_location()};
3940 }
3941
3942 exprt result;
3943 if(
3944 identifier == CPROVER_PREFIX "saturating_minus" ||
3945 identifier == "__builtin_elementwise_sub_sat")
3946 {
3947 result = saturating_minus_exprt{expr.arguments()[0], expr.arguments()[1]};
3948 }
3949 else if(
3950 identifier == CPROVER_PREFIX "saturating_plus" ||
3951 identifier == "__builtin_elementwise_add_sat")
3952 {
3953 result = saturating_plus_exprt{expr.arguments()[0], expr.arguments()[1]};
3954 }
3955 else
3957
3959 result.add_source_location() = expr.source_location();
3960
3961 return result;
3962}
3963
3968{
3969 const exprt &f_op=expr.function();
3970 const code_typet &code_type=to_code_type(f_op.type());
3971 exprt::operandst &arguments=expr.arguments();
3972 const code_typet::parameterst &parameters = code_type.parameters();
3973
3974 // no. of arguments test
3975
3976 if(code_type.get_bool(ID_C_incomplete))
3977 {
3978 // can't check
3979 }
3980 else if(code_type.is_KnR())
3981 {
3982 // We are generous on KnR; any number is ok.
3983 // We will fill in missing ones with "nondet".
3984 for(std::size_t i = arguments.size(); i < parameters.size(); ++i)
3985 {
3986 arguments.push_back(
3987 side_effect_expr_nondett{parameters[i].type(), expr.source_location()});
3988 }
3989 }
3990 else if(code_type.has_ellipsis())
3991 {
3992 if(parameters.size() > arguments.size())
3993 {
3995 error() << "not enough function arguments" << eom;
3996 throw 0;
3997 }
3998 }
3999 else if(parameters.size() != arguments.size())
4000 {
4002 error() << "wrong number of function arguments: "
4003 << "expected " << parameters.size() << ", but got "
4004 << arguments.size() << eom;
4005 throw 0;
4006 }
4007
4008 for(std::size_t i=0; i<arguments.size(); i++)
4009 {
4010 exprt &op=arguments[i];
4011
4012 if(op.is_nil())
4013 {
4014 // ignore
4015 }
4016 else if(i < parameters.size())
4017 {
4018 const code_typet::parametert &parameter = parameters[i];
4019
4020 if(
4021 parameter.is_boolean() && op.id() == ID_side_effect &&
4022 op.get(ID_statement) == ID_assign && op.type().id() != ID_bool)
4023 {
4025 warning() << "assignment where Boolean argument is expected" << eom;
4026 }
4027
4028 implicit_typecast(op, parameter.type());
4029 }
4030 else
4031 {
4032 // don't know type, just do standard conversion
4033
4034 if(op.type().id() == ID_array)
4035 {
4037 dest_type.base_type().set(ID_C_constant, true);
4039 }
4040 }
4041 }
4042}
4043
4045{
4046 // nothing to do
4047}
4048
4050{
4051 exprt &operand = to_unary_expr(expr).op();
4052
4053 const typet &o_type = operand.type();
4054
4055 if(o_type.id()==ID_vector)
4056 {
4057 if(is_number(to_vector_type(o_type).element_type()))
4058 {
4059 // Vector arithmetic.
4060 expr.type()=operand.type();
4061 return;
4062 }
4063 }
4064
4066
4067 if(is_number(operand.type()))
4068 {
4069 expr.type()=operand.type();
4070 return;
4071 }
4072
4074 error() << "operator '" << expr.id() << "' not defined for type '"
4075 << to_string(operand.type()) << "'" << eom;
4076 throw 0;
4077}
4078
4080{
4082
4083 // This is not quite accurate: the standard says the result
4084 // should be of type 'int'.
4085 // We do 'bool' anyway to get more compact formulae. Eventually,
4086 // this should be achieved by means of simplification, and not
4087 // in the frontend.
4088 expr.type()=bool_typet();
4089}
4090
4092 const vector_typet &type0,
4093 const vector_typet &type1)
4094{
4095 // This is relatively restrictive!
4096
4097 // compare dimension
4098 const auto s0 = numeric_cast<mp_integer>(type0.size());
4099 const auto s1 = numeric_cast<mp_integer>(type1.size());
4100 if(!s0.has_value())
4101 return false;
4102 if(!s1.has_value())
4103 return false;
4104 if(*s0 != *s1)
4105 return false;
4106
4107 // compare subtype
4108 if(
4109 (type0.element_type().id() == ID_signedbv ||
4110 type0.element_type().id() == ID_unsignedbv) &&
4111 (type1.element_type().id() == ID_signedbv ||
4112 type1.element_type().id() == ID_unsignedbv) &&
4113 to_bitvector_type(type0.element_type()).get_width() ==
4114 to_bitvector_type(type1.element_type()).get_width())
4115 return true;
4116
4117 return type0.element_type() == type1.element_type();
4118}
4119
4121{
4122 auto &binary_expr = to_binary_expr(expr);
4123 exprt &op0 = binary_expr.op0();
4124 exprt &op1 = binary_expr.op1();
4125
4126 const typet o_type0 = op0.type();
4127 const typet o_type1 = op1.type();
4128
4129 if(o_type0.id()==ID_vector &&
4130 o_type1.id()==ID_vector)
4131 {
4132 if(
4135 is_number(to_vector_type(o_type0).element_type()))
4136 {
4137 // Vector arithmetic has fairly strict typing rules, no promotion
4138 op1 = typecast_exprt::conditional_cast(op1, op0.type());
4139 expr.type()=op0.type();
4140 return;
4141 }
4142 }
4143 else if(
4144 o_type0.id() == ID_vector && o_type1.id() != ID_vector &&
4146 {
4147 // convert op1 to the vector type
4148 op1 = typecast_exprt(op1, o_type0);
4149 expr.type() = o_type0;
4150 return;
4151 }
4152 else if(
4153 o_type0.id() != ID_vector && o_type1.id() == ID_vector &&
4155 {
4156 // convert op0 to the vector type
4157 op0 = typecast_exprt(op0, o_type1);
4158 expr.type() = o_type1;
4159 return;
4160 }
4161
4162 if(expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
4163 {
4165 }
4166 else
4167 {
4168 // promote!
4170 }
4171
4172 const typet &type0 = op0.type();
4173 const typet &type1 = op1.type();
4174
4175 if(expr.id()==ID_plus || expr.id()==ID_minus ||
4176 expr.id()==ID_mult || expr.id()==ID_div)
4177 {
4178 if(type0.id()==ID_pointer || type1.id()==ID_pointer)
4179 {
4181 return;
4182 }
4183 else if(type0==type1)
4184 {
4185 if(is_number(type0))
4186 {
4187 expr.type()=type0;
4188 return;
4189 }
4190 }
4191 }
4192 else if(expr.id()==ID_mod)
4193 {
4194 if(type0==type1)
4195 {
4196 if(type0.id()==ID_signedbv || type0.id()==ID_unsignedbv)
4197 {
4198 expr.type()=type0;
4199 return;
4200 }
4201 }
4202 }
4203 else if(
4204 expr.id() == ID_bitand || expr.id() == ID_bitnand ||
4205 expr.id() == ID_bitxor || expr.id() == ID_bitor)
4206 {
4207 if(type0==type1)
4208 {
4209 if(is_number(type0))
4210 {
4211 expr.type()=type0;
4212 return;
4213 }
4214 else if(type0.id()==ID_bool)
4215 {
4216 if(expr.id()==ID_bitand)
4217 expr.id(ID_and);
4218 else if(expr.id() == ID_bitnand)
4219 expr.id(ID_nand);
4220 else if(expr.id()==ID_bitor)
4221 expr.id(ID_or);
4222 else if(expr.id()==ID_bitxor)
4223 expr.id(ID_xor);
4224 else
4226 expr.type()=type0;
4227 return;
4228 }
4229 }
4230 }
4231 else if(expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
4232 {
4233 if(
4234 type0 == type1 &&
4235 (type0.id() == ID_signedbv || type0.id() == ID_unsignedbv))
4236 {
4237 expr.type() = type0;
4238 return;
4239 }
4240 }
4241
4243 error() << "operator '" << expr.id() << "' not defined for types '"
4244 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4245 << eom;
4246 throw 0;
4247}
4248
4250{
4251 PRECONDITION(expr.id() == ID_shl || expr.id() == ID_shr);
4252
4253 exprt &op0=expr.op0();
4254 exprt &op1=expr.op1();
4255
4256 const typet o_type0 = op0.type();
4257 const typet o_type1 = op1.type();
4258
4259 if(o_type0.id()==ID_vector &&
4260 o_type1.id()==ID_vector)
4261 {
4262 if(
4263 to_vector_type(o_type0).element_type() ==
4264 to_vector_type(o_type1).element_type() &&
4265 is_number(to_vector_type(o_type0).element_type()))
4266 {
4267 // {a0, a1, ..., an} >> {b0, b1, ..., bn} ==
4268 // {a0 >> b0, a1 >> b1, ..., an >> bn}
4269 // Fairly strict typing rules, no promotion
4270 expr.type()=op0.type();
4271 return;
4272 }
4273 }
4274
4275 if(
4276 o_type0.id() == ID_vector &&
4277 is_number(to_vector_type(o_type0).element_type()) && is_number(o_type1))
4278 {
4279 // {a0, a1, ..., an} >> b == {a0 >> b, a1 >> b, ..., an >> b}
4280 op1 = typecast_exprt(op1, o_type0);
4281 expr.type()=op0.type();
4282 return;
4283 }
4284
4285 // must do the promotions _separately_!
4288
4289 if(is_number(op0.type()) &&
4290 is_number(op1.type()))
4291 {
4292 expr.type()=op0.type();
4293
4294 if(expr.id()==ID_shr) // shifting operation depends on types
4295 {
4296 const typet &op0_type = op0.type();
4297
4298 if(op0_type.id()==ID_unsignedbv)
4299 {
4300 expr.id(ID_lshr);
4301 return;
4302 }
4303 else if(op0_type.id()==ID_signedbv)
4304 {
4305 expr.id(ID_ashr);
4306 return;
4307 }
4308 }
4309
4310 return;
4311 }
4312
4314 error() << "operator '" << expr.id() << "' not defined for types '"
4315 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4316 << eom;
4317 throw 0;
4318}
4319
4321{
4322 const typet &type=expr.type();
4323 PRECONDITION(type.id() == ID_pointer);
4324
4325 const typet &base_type = to_pointer_type(type).base_type();
4326
4327 if(
4328 base_type.id() == ID_struct_tag &&
4329 follow_tag(to_struct_tag_type(base_type)).is_incomplete())
4330 {
4332 error() << "pointer arithmetic with unknown object size" << eom;
4333 throw 0;
4334 }
4335 else if(
4336 base_type.id() == ID_union_tag &&
4337 follow_tag(to_union_tag_type(base_type)).is_incomplete())
4338 {
4340 error() << "pointer arithmetic with unknown object size" << eom;
4341 throw 0;
4342 }
4343 else if(
4344 base_type.id() == ID_empty &&
4346 {
4348 error() << "pointer arithmetic with unknown object size" << eom;
4349 throw 0;
4350 }
4351 else if(base_type.id() == ID_empty)
4352 {
4353 // This is a gcc extension.
4354 // https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.html
4356 expr.swap(tc);
4357 }
4358}
4359
4361{
4362 auto &binary_expr = to_binary_expr(expr);
4363 exprt &op0 = binary_expr.op0();
4364 exprt &op1 = binary_expr.op1();
4365
4366 const typet &type0 = op0.type();
4367 const typet &type1 = op1.type();
4368
4369 if(expr.id()==ID_minus ||
4370 (expr.id()==ID_side_effect && expr.get(ID_statement)==ID_assign_minus))
4371 {
4372 if(type0.id()==ID_pointer &&
4373 type1.id()==ID_pointer)
4374 {
4375 if(type0 != type1)
4376 {
4378 "pointer subtraction over different types", expr.source_location()};
4379 }
4380 expr.type()=pointer_diff_type();
4383 return;
4384 }
4385
4386 if(type0.id()==ID_pointer &&
4387 (type1.id()==ID_bool ||
4388 type1.id()==ID_c_bool ||
4389 type1.id()==ID_unsignedbv ||
4390 type1.id()==ID_signedbv ||
4391 type1.id()==ID_c_bit_field ||
4392 type1.id()==ID_c_enum_tag))
4393 {
4395 make_index_type(op1);
4396 expr.type() = op0.type();
4397 return;
4398 }
4399 }
4400 else if(expr.id()==ID_plus ||
4401 (expr.id()==ID_side_effect && expr.get(ID_statement)==ID_assign_plus))
4402 {
4403 exprt *p_op, *int_op;
4404
4405 if(type0.id()==ID_pointer)
4406 {
4407 p_op=&op0;
4408 int_op=&op1;
4409 }
4410 else if(type1.id()==ID_pointer)
4411 {
4412 p_op=&op1;
4413 int_op=&op0;
4414 }
4415 else
4416 {
4417 p_op=int_op=nullptr;
4419 }
4420
4421 const typet &int_op_type = int_op->type();
4422
4423 if(int_op_type.id()==ID_bool ||
4424 int_op_type.id()==ID_c_bool ||
4425 int_op_type.id()==ID_unsignedbv ||
4426 int_op_type.id()==ID_signedbv ||
4429 {
4432 expr.type()=p_op->type();
4433 return;
4434 }
4435 }
4436
4437 irep_idt op_name;
4438
4439 if(expr.id()==ID_side_effect)
4440 op_name=to_side_effect_expr(expr).get_statement();
4441 else
4442 op_name=expr.id();
4443
4445 error() << "operator '" << op_name << "' not defined for types '"
4446 << to_string(type0) << "' and '" << to_string(type1) << "'" << eom;
4447 throw 0;
4448}
4449
4451{
4452 auto &binary_expr = to_binary_expr(expr);
4455
4456 // This is not quite accurate: the standard says the result
4457 // should be of type 'int'.
4458 // We do 'bool' anyway to get more compact formulae. Eventually,
4459 // this should be achieved by means of simplification, and not
4460 // in the frontend.
4461 expr.type()=bool_typet();
4462}
4463
4465 side_effect_exprt &expr)
4466{
4467 const irep_idt &statement=expr.get_statement();
4468
4469 auto &binary_expr = to_binary_expr(expr);
4470 exprt &op0 = binary_expr.op0();
4471 exprt &op1 = binary_expr.op1();
4472
4473 {
4474 const typet &type0=op0.type();
4475
4476 if(type0.id()==ID_empty)
4477 {
4479 error() << "cannot assign void" << eom;
4480 throw 0;
4481 }
4482
4483 if(!op0.get_bool(ID_C_lvalue))
4484 {
4486 error() << "assignment error: '" << to_string(op0) << "' not an lvalue"
4487 << eom;
4488 throw 0;
4489 }
4490
4491 if(type0.get_bool(ID_C_constant))
4492 {
4494 error() << "'" << to_string(op0) << "' is constant" << eom;
4495 throw 0;
4496 }
4497
4498 // refuse to assign arrays
4499 if(type0.id() == ID_array)
4500 {
4502 error() << "direct assignments to arrays not permitted" << eom;
4503 throw 0;
4504 }
4505 }
4506
4507 // Add a cast to the underlying type for bit fields.
4508 if(op0.type() != op1.type() && op0.type().id() == ID_c_bit_field)
4509 {
4510 op1 =
4511 typecast_exprt{op1, to_c_bit_field_type(op0.type()).underlying_type()};
4512 }
4513
4514 const typet o_type0=op0.type();
4515 const typet o_type1=op1.type();
4516
4517 expr.type()=o_type0;
4518
4519 if(statement==ID_assign)
4520 {
4522 return;
4523 }
4524 else if(statement==ID_assign_shl ||
4525 statement==ID_assign_shr)
4526 {
4527 if(o_type0.id() == ID_vector)
4528 {
4530
4531 if(
4532 o_type1.id() == ID_vector &&
4533 vector_o_type0.element_type() ==
4534 to_vector_type(o_type1).element_type() &&
4535 is_number(vector_o_type0.element_type()))
4536 {
4537 return;
4538 }
4539 else if(is_number(vector_o_type0.element_type()) && is_number(o_type1))
4540 {
4541 op1 = typecast_exprt(op1, o_type0);
4542 return;
4543 }
4544 }
4545
4548
4549 if(is_number(op0.type()) && is_number(op1.type()))
4550 {
4551 if(statement==ID_assign_shl)
4552 {
4553 return;
4554 }
4555 else // assign_shr
4556 {
4557 // distinguish arithmetic from logical shifts by looking at type
4558
4559 typet underlying_type=op0.type();
4560
4561 if(underlying_type.id()==ID_unsignedbv ||
4562 underlying_type.id()==ID_c_bool)
4563 {
4565 return;
4566 }
4567 else if(underlying_type.id()==ID_signedbv)
4568 {
4570 return;
4571 }
4572 }
4573 }
4574 }
4575 else if(statement==ID_assign_bitxor ||
4576 statement==ID_assign_bitand ||
4577 statement==ID_assign_bitor)
4578 {
4579 // these are more restrictive
4580 if(o_type0.id()==ID_bool ||
4581 o_type0.id()==ID_c_bool)
4582 {
4584 if(
4585 op1.is_boolean() || op1.type().id() == ID_c_bool ||
4586 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4587 op1.type().id() == ID_signedbv || op1.type().id() == ID_c_bit_field)
4588 {
4589 return;
4590 }
4591 }
4592 else if(o_type0.id()==ID_c_enum_tag ||
4593 o_type0.id()==ID_unsignedbv ||
4594 o_type0.id()==ID_signedbv ||
4595 o_type0.id()==ID_c_bit_field)
4596 {
4598 if(
4599 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4600 op1.type().id() == ID_signedbv || op1.type().id() == ID_c_bit_field)
4601 {
4602 return;
4603 }
4604 }
4605 else if(o_type0.id()==ID_vector &&
4606 o_type1.id()==ID_vector)
4607 {
4608 // We are willing to do a modest amount of conversion
4611 {
4613 return;
4614 }
4615 }
4616 else if(
4617 o_type0.id() == ID_vector &&
4618 (o_type1.id() == ID_bool || o_type1.id() == ID_c_bool ||
4619 o_type1.id() == ID_c_enum_tag || o_type1.id() == ID_unsignedbv ||
4620 o_type1.id() == ID_signedbv))
4621 {
4623 op1 = typecast_exprt(op1, o_type0);
4624 return;
4625 }
4626 }
4627 else
4628 {
4629 if(o_type0.id()==ID_pointer &&
4630 (statement==ID_assign_minus || statement==ID_assign_plus))
4631 {
4633 return;
4634 }
4635 else if(o_type0.id()==ID_vector &&
4636 o_type1.id()==ID_vector)
4637 {
4638 // We are willing to do a modest amount of conversion
4641 {
4643 return;
4644 }
4645 }
4646 else if(o_type0.id() == ID_vector)
4647 {
4649
4650 if(
4651 is_number(op1.type()) || op1.is_boolean() ||
4652 op1.type().id() == ID_c_bool || op1.type().id() == ID_c_enum_tag)
4653 {
4654 op1 = typecast_exprt(op1, o_type0);
4655 return;
4656 }
4657 }
4658 else if(o_type0.id()==ID_bool ||
4659 o_type0.id()==ID_c_bool)
4660 {
4662 if(
4663 op1.is_boolean() || op1.type().id() == ID_c_bool ||
4664 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4665 op1.type().id() == ID_signedbv)
4666 {
4667 return;
4668 }
4669 }
4670 else
4671 {
4673
4674 if(
4675 is_number(op1.type()) || op1.is_boolean() ||
4676 op1.type().id() == ID_c_bool || op1.type().id() == ID_c_enum_tag)
4677 {
4678 return;
4679 }
4680 }
4681 }
4682
4684 error() << "assignment '" << statement << "' not defined for types '"
4685 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4686 << eom;
4687
4688 throw 0;
4689}
4690
4695{
4696public:
4698 {
4699 }
4700
4702 bool operator()(const exprt &e) const
4703 {
4704 return is_constant(e);
4705 }
4706
4707protected:
4709
4712 bool is_constant(const exprt &e) const
4713 {
4714 if(e.id() == ID_infinity)
4715 return true;
4716
4717 if(e.is_constant())
4718 return true;
4719
4720 if(e.id() == ID_address_of)
4721 {
4722 return is_constant_address_of(to_address_of_expr(e).object());
4723 }
4724 else if(
4725 e.id() == ID_typecast || e.id() == ID_array_of || e.id() == ID_plus ||
4726 e.id() == ID_mult || e.id() == ID_array || e.id() == ID_with ||
4727 e.id() == ID_struct || e.id() == ID_union || e.id() == ID_empty_union ||
4728 e.id() == ID_equal || e.id() == ID_notequal || e.id() == ID_lt ||
4729 e.id() == ID_le || e.id() == ID_gt || e.id() == ID_ge ||
4730 e.id() == ID_if || e.id() == ID_not || e.id() == ID_and ||
4731 e.id() == ID_or || e.id() == ID_bitnot || e.id() == ID_bitand ||
4732 e.id() == ID_bitor || e.id() == ID_bitxor || e.id() == ID_vector)
4733 {
4734 return std::all_of(
4735 e.operands().begin(), e.operands().end(), [this](const exprt &op) {
4736 return is_constant(op);
4737 });
4738 }
4739
4740 return false;
4741 }
4742
4744 bool is_constant_address_of(const exprt &e) const
4745 {
4746 if(e.id() == ID_symbol)
4747 {
4748 return e.type().id() == ID_code ||
4749 ns.lookup(to_symbol_expr(e).get_identifier()).is_static_lifetime;
4750 }
4751 else if(e.id() == ID_array && e.get_bool(ID_C_string_constant))
4752 return true;
4753 else if(e.id() == ID_label)
4754 return true;
4755 else if(e.id() == ID_index)
4756 {
4758
4759 return is_constant_address_of(index_expr.array()) &&
4760 is_constant(index_expr.index());
4761 }
4762 else if(e.id() == ID_member)
4763 {
4764 return is_constant_address_of(to_member_expr(e).compound());
4765 }
4766 else if(e.id() == ID_dereference)
4767 {
4769
4770 return is_constant(deref.pointer());
4771 }
4772 else if(e.id() == ID_string_constant)
4773 return true;
4774
4775 return false;
4776 }
4777};
4778
4780{
4781 source_locationt location = expr.find_source_location();
4782
4783 // Floating-point expressions may require a rounding mode.
4784 // ISO 9899:1999 F.7.2 says that the default is "round to nearest".
4785 // Some compilers have command-line options to override.
4786 const auto rounding_mode =
4788 adjust_float_expressions(expr, rounding_mode);
4789
4790 simplify(expr, *this);
4791 expr.add_source_location() = location;
4792
4793 if(!is_compile_time_constantt(*this)(expr))
4794 {
4795 error().source_location = location;
4796 error() << "expected constant expression, but got '" << to_string(expr)
4797 << "'" << eom;
4798 throw 0;
4799 }
4800}
4801
4803{
4804 source_locationt location = expr.find_source_location();
4805 make_constant(expr);
4806 make_index_type(expr);
4807 simplify(expr, *this);
4808 expr.add_source_location() = location;
4809
4810 if(!is_compile_time_constantt(*this)(expr))
4811 {
4812 error().source_location = location;
4813 error() << "conversion to integer constant failed" << eom;
4814 throw 0;
4815 }
4816}
4817
4819 const exprt &expr,
4820 const irep_idt &id,
4821 const std::string &message) const
4822{
4823 if(!has_subexpr(expr, id))
4824 return;
4825
4827 error() << message << eom;
4828 throw 0;
4829}
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:3118
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:3246
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:2502
Array index operator.
Definition std_expr.h:1470
An expression denoting infinity.
Definition std_expr.h:3271
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:3255
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:3237
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:2582
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3064
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3189
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