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