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).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).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()).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.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()).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).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
2406 const auto builtin_code_type =
2408
2409 INVARIANT(
2410 builtin_code_type.has_ellipsis() &&
2411 builtin_code_type.parameters().empty(),
2412 "Shadow memory builtins should be an ellipsis with 0 parameter");
2413
2414 // Add the symbol to the symbol table if it is not present yet.
2416 {
2417 symbolt new_symbol{
2419 new_symbol.base_name = shadow_memory_builtin_id;
2420 new_symbol.location = f_op.source_location();
2421 // Add an empty implementation to avoid warnings about missing
2422 // implementation later on
2423 new_symbol.value = code_blockt{};
2424
2425 symbol_table.add(new_symbol);
2426 }
2427
2428 // Swap the current `function` field with the newly generated
2429 // `shadow_memory_builtin` `symbol_exprt` and carry on with typechecking
2430 f_op = std::move(*shadow_memory_builtin);
2431 }
2432 else if(
2434 identifier, expr.arguments(), f_op.source_location()))
2435 {
2437 auto &parameters = to_code_type(gcc_polymorphic->type()).parameters();
2438 INVARIANT(
2439 !parameters.empty(),
2440 "GCC polymorphic built-ins should have at least one parameter");
2441
2442 // For all atomic/sync polymorphic built-ins (which are the ones handled
2443 // by typecheck_gcc_polymorphic_builtin), looking at the first parameter
2444 // suffices to distinguish different implementations.
2445 if(parameters.front().type().id() == ID_pointer)
2446 {
2448 id2string(identifier) + "_" +
2450 to_pointer_type(parameters.front().type()).base_type(), *this);
2451 }
2452 else
2453 {
2455 id2string(identifier) + "_" +
2456 type_to_partial_identifier(parameters.front().type(), *this);
2457 }
2459
2461 {
2462 for(std::size_t i = 0; i < parameters.size(); ++i)
2463 {
2464 const std::string base_name = "p_" + std::to_string(i);
2465
2466 parameter_symbolt new_symbol;
2467
2468 new_symbol.name =
2469 id2string(identifier_with_type) + "::" + base_name;
2470 new_symbol.base_name = base_name;
2471 new_symbol.location = f_op.source_location();
2472 new_symbol.type = parameters[i].type();
2473 new_symbol.is_parameter = true;
2474 new_symbol.is_lvalue = true;
2475 new_symbol.mode = ID_C;
2476
2477 parameters[i].set_identifier(new_symbol.name);
2478 parameters[i].set_base_name(new_symbol.base_name);
2479
2480 symbol_table.add(new_symbol);
2481 }
2482
2483 symbolt new_symbol{
2485 new_symbol.base_name = identifier_with_type;
2486 new_symbol.location = f_op.source_location();
2487 code_blockt implementation =
2490 return_type = to_code_type(gcc_polymorphic->type()).return_type();
2491 typecheck_code(implementation);
2493 new_symbol.value = implementation;
2494
2495 symbol_table.add(new_symbol);
2496 }
2497
2498 f_op = std::move(*gcc_polymorphic);
2499 }
2500 else
2501 {
2502 // This is an undeclared function that's not a builtin.
2503 // Let's just add it.
2504 // We do a bit of return-type guessing, but just a bit.
2506
2507 // The following isn't really right and sound, but there
2508 // are too many idiots out there who use malloc and the like
2509 // without the right header file.
2510 if(identifier=="malloc" ||
2511 identifier=="realloc" ||
2512 identifier=="reallocf" ||
2513 identifier=="valloc")
2514 {
2516 }
2517
2518 symbolt new_symbol{
2519 identifier, code_typet({}, guessed_return_type), mode};
2520 new_symbol.base_name=identifier;
2521 new_symbol.location=expr.source_location();
2522 new_symbol.type.set(ID_C_incomplete, true);
2523
2524 // TODO: should also guess some argument types
2525
2527 move_symbol(new_symbol, symbol_ptr);
2528
2529 // We increase the verbosity level of the warning
2530 // for gcc/clang __builtin_ functions, since there are too many.
2531 if(identifier.starts_with("__builtin_"))
2532 {
2533 debug().source_location = f_op.find_source_location();
2534 debug() << "builtin '" << identifier << "' is unknown" << eom;
2535 }
2536 else
2537 {
2538 warning().source_location = f_op.find_source_location();
2539 warning() << "function '" << identifier << "' is not declared" << eom;
2540 }
2541 }
2542 }
2543 }
2544
2545 // typecheck it now
2547
2548 const typet f_op_type = f_op.type();
2549
2551 {
2552 const auto &mathematical_function_type =
2554
2555 // check number of arguments
2556 if(expr.arguments().size() != mathematical_function_type.domain().size())
2557 {
2558 error().source_location = f_op.source_location();
2559 error() << "expected " << mathematical_function_type.domain().size()
2560 << " arguments but got " << expr.arguments().size() << eom;
2561 throw 0;
2562 }
2563
2564 // check the types of the arguments
2565 for(auto &p :
2566 make_range(expr.arguments()).zip(mathematical_function_type.domain()))
2567 {
2568 if(p.first.type() != p.second)
2569 {
2570 error().source_location = p.first.source_location();
2571 error() << "expected argument of type " << to_string(p.second)
2572 << " but got " << to_string(p.first.type()) << eom;
2573 throw 0;
2574 }
2575 }
2576
2577 function_application_exprt function_application(f_op, expr.arguments());
2578
2579 function_application.add_source_location() = expr.source_location();
2580
2581 expr.swap(function_application);
2582 return;
2583 }
2584
2585 if(f_op_type.id()!=ID_pointer)
2586 {
2587 error().source_location = f_op.source_location();
2588 error() << "expected function/function pointer as argument but got '"
2589 << to_string(f_op_type) << "'" << eom;
2590 throw 0;
2591 }
2592
2593 // do implicit dereference
2594 if(f_op.id() == ID_address_of && f_op.get_bool(ID_C_implicit))
2595 {
2596 f_op = to_address_of_expr(f_op).object();
2597 }
2598 else
2599 {
2601 tmp.set(ID_C_implicit, true);
2602 tmp.add_source_location()=f_op.source_location();
2603 f_op.swap(tmp);
2604 }
2605
2606 if(f_op.type().id()!=ID_code)
2607 {
2608 error().source_location = f_op.source_location();
2609 error() << "expected code as argument" << eom;
2610 throw 0;
2611 }
2612
2613 const code_typet &code_type=to_code_type(f_op.type());
2614
2615 expr.type()=code_type.return_type();
2616
2618
2619 if(tmp.is_not_nil())
2620 expr.swap(tmp);
2621 else
2623}
2624
2627{
2628 const exprt &f_op=expr.function();
2629 const source_locationt &source_location=expr.source_location();
2630
2631 // some built-in functions
2632 if(f_op.id()!=ID_symbol)
2633 return nil_exprt();
2634
2635 const irep_idt &identifier = to_symbol_expr(f_op).identifier();
2636
2637 if(identifier == CPROVER_PREFIX "pointer_equals")
2638 {
2639 if(expr.arguments().size() != 2)
2640 {
2641 error().source_location = f_op.source_location();
2642 error() << CPROVER_PREFIX "pointer_equals expects two operands; "
2643 << expr.arguments().size() << "provided." << eom;
2644 throw 0;
2645 }
2647 return nil_exprt();
2648 }
2649 else if(identifier == CPROVER_PREFIX "is_fresh")
2650 {
2651 if(expr.arguments().size() != 2)
2652 {
2653 error().source_location = f_op.source_location();
2654 error() << CPROVER_PREFIX "is_fresh expects two operands; "
2655 << expr.arguments().size() << "provided." << eom;
2656 throw 0;
2657 }
2659 return nil_exprt();
2660 }
2661 else if(identifier == CPROVER_PREFIX "obeys_contract")
2662 {
2664 // returning nil leaves the call expression in place
2665 return nil_exprt();
2666 }
2667 else if(identifier == CPROVER_PREFIX "pointer_in_range_dfcc")
2668 {
2669 // same as pointer_in_range with experimental support for DFCC contracts
2670 // -- do not use
2671 if(expr.arguments().size() != 3)
2672 {
2674 CPROVER_PREFIX "pointer_in_range_dfcc expects three arguments",
2675 expr.source_location()};
2676 }
2677
2678 for(const auto &arg : expr.arguments())
2679 {
2680 if(arg.type().id() != ID_pointer)
2681 {
2684 "pointer_in_range_dfcc expects pointer-typed arguments",
2685 arg.source_location()};
2686 }
2687 }
2688 return nil_exprt();
2689 }
2690 else if(identifier == CPROVER_PREFIX "same_object")
2691 {
2692 if(expr.arguments().size()!=2)
2693 {
2694 error().source_location = f_op.source_location();
2695 error() << "same_object expects two operands" << eom;
2696 throw 0;
2697 }
2698
2700
2702 same_object(expr.arguments()[0], expr.arguments()[1]);
2703 same_object_expr.add_source_location()=source_location;
2704
2705 return same_object_expr;
2706 }
2707 else if(identifier==CPROVER_PREFIX "get_must")
2708 {
2709 if(expr.arguments().size()!=2)
2710 {
2711 error().source_location = f_op.source_location();
2712 error() << "get_must expects two operands" << eom;
2713 throw 0;
2714 }
2715
2717
2719 expr.arguments()[0], ID_get_must, expr.arguments()[1]);
2720 get_must_expr.add_source_location()=source_location;
2721
2722 return std::move(get_must_expr);
2723 }
2724 else if(identifier==CPROVER_PREFIX "get_may")
2725 {
2726 if(expr.arguments().size()!=2)
2727 {
2728 error().source_location = f_op.source_location();
2729 error() << "get_may expects two operands" << eom;
2730 throw 0;
2731 }
2732
2734
2736 expr.arguments()[0], ID_get_may, expr.arguments()[1]);
2737 get_may_expr.add_source_location()=source_location;
2738
2739 return std::move(get_may_expr);
2740 }
2741 else if(identifier == CPROVER_PREFIX "is_invalid_pointer")
2742 {
2743 if(expr.arguments().size()!=1)
2744 {
2745 error().source_location = f_op.source_location();
2746 error() << "is_invalid_pointer expects one operand" << eom;
2747 throw 0;
2748 }
2749
2751
2753 same_object_expr.add_source_location()=source_location;
2754
2755 return same_object_expr;
2756 }
2757 else if(identifier==CPROVER_PREFIX "buffer_size")
2758 {
2759 if(expr.arguments().size()!=1)
2760 {
2761 error().source_location = f_op.source_location();
2762 error() << "buffer_size expects one operand" << eom;
2763 throw 0;
2764 }
2765
2767
2768 exprt buffer_size_expr("buffer_size", size_type());
2769 buffer_size_expr.operands()=expr.arguments();
2770 buffer_size_expr.add_source_location()=source_location;
2771
2772 return buffer_size_expr;
2773 }
2774 else if(identifier == CPROVER_PREFIX "is_list")
2775 {
2776 // experimental feature for CHC encodings -- do not use
2777 if(expr.arguments().size() != 1)
2778 {
2779 error().source_location = f_op.source_location();
2780 error() << "is_list expects one operand" << eom;
2781 throw 0;
2782 }
2783
2785
2786 if(
2787 expr.arguments()[0].type().id() != ID_pointer ||
2788 to_pointer_type(expr.arguments()[0].type()).base_type().id() !=
2790 {
2791 error().source_location = expr.arguments()[0].source_location();
2792 error() << "is_list expects a struct-pointer operand" << eom;
2793 throw 0;
2794 }
2795
2796 predicate_exprt is_list_expr("is_list");
2797 is_list_expr.operands() = expr.arguments();
2798 is_list_expr.add_source_location() = source_location;
2799
2800 return std::move(is_list_expr);
2801 }
2802 else if(identifier == CPROVER_PREFIX "is_dll")
2803 {
2804 // experimental feature for CHC encodings -- do not use
2805 if(expr.arguments().size() != 1)
2806 {
2807 error().source_location = f_op.source_location();
2808 error() << "is_dll expects one operand" << eom;
2809 throw 0;
2810 }
2811
2813
2814 if(
2815 expr.arguments()[0].type().id() != ID_pointer ||
2816 to_pointer_type(expr.arguments()[0].type()).base_type().id() !=
2818 {
2819 error().source_location = expr.arguments()[0].source_location();
2820 error() << "is_dll expects a struct-pointer operand" << eom;
2821 throw 0;
2822 }
2823
2824 predicate_exprt is_dll_expr("is_dll");
2825 is_dll_expr.operands() = expr.arguments();
2826 is_dll_expr.add_source_location() = source_location;
2827
2828 return std::move(is_dll_expr);
2829 }
2830 else if(identifier == CPROVER_PREFIX "is_cyclic_dll")
2831 {
2832 // experimental feature for CHC encodings -- do not use
2833 if(expr.arguments().size() != 1)
2834 {
2835 error().source_location = f_op.source_location();
2836 error() << "is_cyclic_dll expects one operand" << eom;
2837 throw 0;
2838 }
2839
2841
2842 if(
2843 expr.arguments()[0].type().id() != ID_pointer ||
2844 to_pointer_type(expr.arguments()[0].type()).base_type().id() !=
2846 {
2847 error().source_location = expr.arguments()[0].source_location();
2848 error() << "is_cyclic_dll expects a struct-pointer operand" << eom;
2849 throw 0;
2850 }
2851
2852 predicate_exprt is_cyclic_dll_expr("is_cyclic_dll");
2853 is_cyclic_dll_expr.operands() = expr.arguments();
2854 is_cyclic_dll_expr.add_source_location() = source_location;
2855
2856 return std::move(is_cyclic_dll_expr);
2857 }
2858 else if(identifier == CPROVER_PREFIX "is_sentinel_dll")
2859 {
2860 // experimental feature for CHC encodings -- do not use
2861 if(expr.arguments().size() != 2 && expr.arguments().size() != 3)
2862 {
2863 error().source_location = f_op.source_location();
2864 error() << "is_sentinel_dll expects two or three operands" << eom;
2865 throw 0;
2866 }
2867
2869
2871 args_no_cast.reserve(expr.arguments().size());
2872 for(const auto &argument : expr.arguments())
2873 {
2875 if(
2876 args_no_cast.back().type().id() != ID_pointer ||
2877 to_pointer_type(args_no_cast.back().type()).base_type().id() !=
2879 {
2880 error().source_location = expr.arguments()[0].source_location();
2881 error() << "is_sentinel_dll_node expects struct-pointer operands"
2882 << eom;
2883 throw 0;
2884 }
2885 }
2886
2887 predicate_exprt is_sentinel_dll_expr("is_sentinel_dll");
2889 is_sentinel_dll_expr.add_source_location() = source_location;
2890
2891 return std::move(is_sentinel_dll_expr);
2892 }
2893 else if(identifier == CPROVER_PREFIX "is_cstring")
2894 {
2895 // experimental feature for CHC encodings -- do not use
2896 if(expr.arguments().size() != 1)
2897 {
2898 error().source_location = f_op.source_location();
2899 error() << "is_cstring expects one operand" << eom;
2900 throw 0;
2901 }
2902
2904
2905 if(expr.arguments()[0].type().id() != ID_pointer)
2906 {
2907 error().source_location = expr.arguments()[0].source_location();
2908 error() << "is_cstring expects a pointer operand" << eom;
2909 throw 0;
2910 }
2911
2913 is_cstring_expr.add_source_location() = source_location;
2914
2915 return std::move(is_cstring_expr);
2916 }
2917 else if(identifier == CPROVER_PREFIX "cstrlen")
2918 {
2919 // experimental feature for CHC encodings -- do not use
2920 if(expr.arguments().size() != 1)
2921 {
2922 error().source_location = f_op.source_location();
2923 error() << "cstrlen expects one operand" << eom;
2924 throw 0;
2925 }
2926
2928
2929 if(expr.arguments()[0].type().id() != ID_pointer)
2930 {
2931 error().source_location = expr.arguments()[0].source_location();
2932 error() << "cstrlen expects a pointer operand" << eom;
2933 throw 0;
2934 }
2935
2937 cstrlen_expr.add_source_location() = source_location;
2938
2939 return std::move(cstrlen_expr);
2940 }
2941 else if(identifier==CPROVER_PREFIX "is_zero_string")
2942 {
2943 if(expr.arguments().size()!=1)
2944 {
2945 error().source_location = f_op.source_location();
2946 error() << "is_zero_string expects one operand" << eom;
2947 throw 0;
2948 }
2949
2951
2953 "is_zero_string", expr.arguments()[0], c_bool_type());
2954 is_zero_string_expr.set(ID_C_lvalue, true); // make it an lvalue
2955 is_zero_string_expr.add_source_location()=source_location;
2956
2957 return std::move(is_zero_string_expr);
2958 }
2959 else if(identifier==CPROVER_PREFIX "zero_string_length")
2960 {
2961 if(expr.arguments().size()!=1)
2962 {
2963 error().source_location = f_op.source_location();
2964 error() << "zero_string_length expects one operand" << eom;
2965 throw 0;
2966 }
2967
2969
2970 exprt zero_string_length_expr("zero_string_length", size_type());
2971 zero_string_length_expr.operands()=expr.arguments();
2972 zero_string_length_expr.set(ID_C_lvalue, true); // make it an lvalue
2973 zero_string_length_expr.add_source_location()=source_location;
2974
2976 }
2977 else if(identifier==CPROVER_PREFIX "DYNAMIC_OBJECT")
2978 {
2979 if(expr.arguments().size()!=1)
2980 {
2981 error().source_location = f_op.source_location();
2982 error() << "dynamic_object expects one argument" << eom;
2983 throw 0;
2984 }
2985
2987
2989 is_dynamic_object_expr.add_source_location() = source_location;
2990
2992 }
2993 else if(identifier == CPROVER_PREFIX "LIVE_OBJECT")
2994 {
2995 if(expr.arguments().size() != 1)
2996 {
2997 error().source_location = f_op.source_location();
2998 error() << "live_object expects one argument" << eom;
2999 throw 0;
3000 }
3001
3003
3005 live_object_expr.add_source_location() = source_location;
3006
3007 return live_object_expr;
3008 }
3009 else if(identifier == CPROVER_PREFIX "pointer_in_range")
3010 {
3011 if(expr.arguments().size() != 3)
3012 {
3013 error().source_location = f_op.source_location();
3014 error() << "pointer_in_range expects three arguments" << eom;
3015 throw 0;
3016 }
3017
3019
3021 expr.arguments()[0], expr.arguments()[1], expr.arguments()[2]);
3022 pointer_in_range_expr.add_source_location() = source_location;
3023
3024 return pointer_in_range_expr;
3025 }
3026 else if(identifier == CPROVER_PREFIX "WRITEABLE_OBJECT")
3027 {
3028 if(expr.arguments().size() != 1)
3029 {
3030 error().source_location = f_op.source_location();
3031 error() << "writeable_object expects one argument" << eom;
3032 throw 0;
3033 }
3034
3036
3038 writeable_object_expr.add_source_location() = source_location;
3039
3040 return writeable_object_expr;
3041 }
3042 else if(identifier == CPROVER_PREFIX "separate")
3043 {
3044 // experimental feature for CHC encodings -- do not use
3045 if(expr.arguments().size() < 2)
3046 {
3047 error().source_location = f_op.source_location();
3048 error() << "separate expects two or more arguments" << eom;
3049 throw 0;
3050 }
3051
3053
3055 separate_expr.add_source_location() = source_location;
3056
3057 return separate_expr;
3058 }
3059 else if(identifier==CPROVER_PREFIX "POINTER_OFFSET")
3060 {
3061 if(expr.arguments().size()!=1)
3062 {
3063 error().source_location = f_op.source_location();
3064 error() << "pointer_offset expects one argument" << eom;
3065 throw 0;
3066 }
3067
3069
3071 pointer_offset_expr.add_source_location()=source_location;
3072
3074 }
3075 else if(identifier == CPROVER_PREFIX "OBJECT_SIZE")
3076 {
3077 if(expr.arguments().size() != 1)
3078 {
3079 error().source_location = f_op.source_location();
3080 error() << "object_size expects one operand" << eom;
3081 throw 0;
3082 }
3083
3085
3087 object_size_expr.add_source_location() = source_location;
3088
3089 return std::move(object_size_expr);
3090 }
3091 else if(identifier==CPROVER_PREFIX "POINTER_OBJECT")
3092 {
3093 if(expr.arguments().size()!=1)
3094 {
3095 error().source_location = f_op.source_location();
3096 error() << "pointer_object expects one argument" << eom;
3097 throw 0;
3098 }
3099
3101
3103 pointer_object_expr.add_source_location() = source_location;
3104
3106 }
3107 else if(identifier=="__builtin_bswap16" ||
3108 identifier=="__builtin_bswap32" ||
3109 identifier=="__builtin_bswap64")
3110 {
3111 if(expr.arguments().size()!=1)
3112 {
3113 error().source_location = f_op.source_location();
3114 error() << identifier << " expects one operand" << eom;
3115 throw 0;
3116 }
3117
3119
3120 // these are hard-wired to 8 bits according to the gcc manual
3121 bswap_exprt bswap_expr(expr.arguments().front(), 8, expr.type());
3122 bswap_expr.add_source_location()=source_location;
3123
3124 return std::move(bswap_expr);
3125 }
3126 else if(
3127 identifier == "__builtin_rotateleft8" ||
3128 identifier == "__builtin_rotateleft16" ||
3129 identifier == "__builtin_rotateleft32" ||
3130 identifier == "__builtin_rotateleft64" ||
3131 identifier == "__builtin_rotateright8" ||
3132 identifier == "__builtin_rotateright16" ||
3133 identifier == "__builtin_rotateright32" ||
3134 identifier == "__builtin_rotateright64")
3135 {
3136 // clang only
3137 if(expr.arguments().size() != 2)
3138 {
3139 error().source_location = f_op.source_location();
3140 error() << identifier << " expects two operands" << eom;
3141 throw 0;
3142 }
3143
3145
3146 irep_idt id = (identifier == "__builtin_rotateleft8" ||
3147 identifier == "__builtin_rotateleft16" ||
3148 identifier == "__builtin_rotateleft32" ||
3149 identifier == "__builtin_rotateleft64")
3150 ? ID_rol
3151 : ID_ror;
3152
3153 shift_exprt rotate_expr(expr.arguments()[0], id, expr.arguments()[1]);
3154 rotate_expr.add_source_location() = source_location;
3155
3156 return std::move(rotate_expr);
3157 }
3158 else if(identifier=="__builtin_nontemporal_load")
3159 {
3160 if(expr.arguments().size()!=1)
3161 {
3162 error().source_location = f_op.source_location();
3163 error() << identifier << " expects one operand" << eom;
3164 throw 0;
3165 }
3166
3168
3169 // these return the subtype of the argument
3170 exprt &ptr_arg=expr.arguments().front();
3171
3172 if(ptr_arg.type().id()!=ID_pointer)
3173 {
3174 error().source_location = f_op.source_location();
3175 error() << "__builtin_nontemporal_load takes pointer as argument" << eom;
3176 throw 0;
3177 }
3178
3179 expr.type() = to_pointer_type(expr.arguments().front().type()).base_type();
3180
3181 return expr;
3182 }
3183 else if(
3184 identifier == "__builtin_fpclassify" ||
3185 identifier == CPROVER_PREFIX "fpclassify")
3186 {
3187 if(expr.arguments().size() != 6)
3188 {
3189 error().source_location = f_op.source_location();
3190 error() << identifier << " expects six arguments" << eom;
3191 throw 0;
3192 }
3193
3195
3196 // This gets 5 integers followed by a float or double.
3197 // The five integers are the return values for the cases
3198 // FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL and FP_ZERO.
3199 // gcc expects this to be able to produce compile-time constants.
3200
3201 const exprt &fp_value = expr.arguments()[5];
3202
3203 if(fp_value.type().id() != ID_floatbv)
3204 {
3205 error().source_location = fp_value.source_location();
3206 error() << "non-floating-point argument for " << identifier << eom;
3207 throw 0;
3208 }
3209
3210 const auto &floatbv_type = to_floatbv_type(fp_value.type());
3211
3212 const exprt zero = ieee_floatt::zero(floatbv_type).to_expr();
3213
3214 const auto &arguments = expr.arguments();
3215
3216 return if_exprt(
3218 arguments[0],
3219 if_exprt(
3221 arguments[1],
3222 if_exprt(
3224 arguments[2],
3225 if_exprt(
3227 arguments[4],
3228 arguments[3])))); // subnormal
3229 }
3230 else if(identifier==CPROVER_PREFIX "isnanf" ||
3231 identifier==CPROVER_PREFIX "isnand" ||
3232 identifier==CPROVER_PREFIX "isnanld" ||
3233 identifier=="__builtin_isnan")
3234 {
3235 if(expr.arguments().size()!=1)
3236 {
3237 error().source_location = f_op.source_location();
3238 error() << "isnan expects one operand" << eom;
3239 throw 0;
3240 }
3241
3243
3244 isnan_exprt isnan_expr(expr.arguments().front());
3245 isnan_expr.add_source_location()=source_location;
3246
3248 }
3249 else if(identifier==CPROVER_PREFIX "isfinitef" ||
3250 identifier==CPROVER_PREFIX "isfinited" ||
3251 identifier==CPROVER_PREFIX "isfiniteld")
3252 {
3253 if(expr.arguments().size()!=1)
3254 {
3255 error().source_location = f_op.source_location();
3256 error() << "isfinite expects one operand" << eom;
3257 throw 0;
3258 }
3259
3261
3262 isfinite_exprt isfinite_expr(expr.arguments().front());
3263 isfinite_expr.add_source_location()=source_location;
3264
3266 }
3267 else if(
3268 identifier == CPROVER_PREFIX "inf" || identifier == "__builtin_inf" ||
3269 identifier == "__builtin_huge_val")
3270 {
3274 inf_expr.add_source_location()=source_location;
3275
3276 return std::move(inf_expr);
3277 }
3278 else if(
3279 identifier == CPROVER_PREFIX "inff" || identifier == "__builtin_inff" ||
3280 identifier == "__builtin_huge_valf")
3281 {
3285 inff_expr.add_source_location()=source_location;
3286
3287 return std::move(inff_expr);
3288 }
3289 else if(
3290 identifier == CPROVER_PREFIX "infl" || identifier == "__builtin_infl" ||
3291 identifier == "__builtin_huge_vall")
3292 {
3296 infl_expr.add_source_location()=source_location;
3297
3298 return std::move(infl_expr);
3299 }
3300 else if(
3301 identifier == CPROVER_PREFIX "round_to_integralf" ||
3302 identifier == CPROVER_PREFIX "round_to_integrald" ||
3303 identifier == CPROVER_PREFIX "round_to_integralld")
3304 {
3305 if(expr.arguments().size() != 2)
3306 {
3307 error().source_location = f_op.source_location();
3308 error() << identifier << " expects two arguments" << eom;
3309 throw 0;
3310 }
3311
3314 round_to_integral_expr.add_source_location() = source_location;
3315
3316 return std::move(round_to_integral_expr);
3317 }
3318 else if(
3319 identifier == CPROVER_PREFIX "abs" || identifier == CPROVER_PREFIX "labs" ||
3320 identifier == CPROVER_PREFIX "llabs" ||
3321 identifier == CPROVER_PREFIX "imaxabs" ||
3322 identifier == CPROVER_PREFIX "fabs" ||
3323 identifier == CPROVER_PREFIX "fabsf" ||
3324 identifier == CPROVER_PREFIX "fabsl")
3325 {
3326 if(expr.arguments().size()!=1)
3327 {
3328 error().source_location = f_op.source_location();
3329 error() << "abs-functions expect one operand" << eom;
3330 throw 0;
3331 }
3332
3334
3335 abs_exprt abs_expr(expr.arguments().front());
3336 abs_expr.add_source_location()=source_location;
3337
3338 return std::move(abs_expr);
3339 }
3340 else if(
3341 identifier == CPROVER_PREFIX "fmod" ||
3342 identifier == CPROVER_PREFIX "fmodf" ||
3343 identifier == CPROVER_PREFIX "fmodl")
3344 {
3345 if(expr.arguments().size() != 2)
3346 {
3347 error().source_location = f_op.source_location();
3348 error() << "fmod-functions expect two operands" << eom;
3349 throw 0;
3350 }
3351
3353
3354 // Note that the semantics differ from the
3355 // "floating point remainder" operation as defined by IEEE.
3356 // Note that these do not take a rounding mode.
3358 expr.arguments()[0], ID_floatbv_mod, expr.arguments()[1]);
3359
3360 fmod_expr.add_source_location() = source_location;
3361
3362 return std::move(fmod_expr);
3363 }
3364 else if(
3365 identifier == CPROVER_PREFIX "remainder" ||
3366 identifier == CPROVER_PREFIX "remainderf" ||
3367 identifier == CPROVER_PREFIX "remainderl")
3368 {
3369 if(expr.arguments().size() != 2)
3370 {
3371 error().source_location = f_op.source_location();
3372 error() << "remainder-functions expect two operands" << eom;
3373 throw 0;
3374 }
3375
3377
3378 // The semantics of these functions is meant to match the
3379 // "floating point remainder" operation as defined by IEEE.
3380 // Note that these do not take a rounding mode.
3382 expr.arguments()[0], ID_floatbv_rem, expr.arguments()[1]);
3383
3384 floatbv_rem_expr.add_source_location() = source_location;
3385
3386 return std::move(floatbv_rem_expr);
3387 }
3388 else if(
3389 identifier == CPROVER_PREFIX "fma" || identifier == CPROVER_PREFIX "fmaf" ||
3390 identifier == CPROVER_PREFIX "fmal")
3391 {
3392 if(expr.arguments().size() != 3)
3393 {
3394 error().source_location = f_op.source_location();
3395 error() << "fma-functions expect three operands" << eom;
3396 throw 0;
3397 }
3398
3400
3401 // Create with 3 operands; adjust_float_expressions adds rounding mode
3402 typet result_type = expr.arguments()[0].type();
3404 ID_floatbv_fma, expr.arguments(), std::move(result_type));
3405
3406 fma_expr.add_source_location() = source_location;
3407
3408 return std::move(fma_expr);
3409 }
3410 else if(identifier==CPROVER_PREFIX "allocate")
3411 {
3412 if(expr.arguments().size()!=2)
3413 {
3414 error().source_location = f_op.source_location();
3415 error() << "allocate expects two operands" << eom;
3416 throw 0;
3417 }
3418
3420
3421 side_effect_exprt malloc_expr(ID_allocate, expr.type(), source_location);
3422 malloc_expr.operands()=expr.arguments();
3423
3424 return std::move(malloc_expr);
3425 }
3426 else if(
3427 (identifier == CPROVER_PREFIX "old") ||
3428 (identifier == CPROVER_PREFIX "loop_entry"))
3429 {
3430 if(expr.arguments().size() != 1)
3431 {
3432 error().source_location = f_op.source_location();
3433 error() << identifier << " expects one operand" << eom;
3434 throw 0;
3435 }
3436
3437 const auto &param_id = expr.arguments().front().id();
3438 if(!(param_id == ID_dereference || param_id == ID_member ||
3441 param_id == ID_index))
3442 {
3443 error().source_location = f_op.source_location();
3444 error() << "Tracking history of " << param_id
3445 << " expressions is not supported yet." << eom;
3446 throw 0;
3447 }
3448
3449 irep_idt id = identifier == CPROVER_PREFIX "old" ? ID_old : ID_loop_entry;
3450
3451 history_exprt old_expr(expr.arguments()[0], id);
3452 old_expr.add_source_location() = source_location;
3453
3454 return std::move(old_expr);
3455 }
3456 else if(identifier==CPROVER_PREFIX "isinff" ||
3457 identifier==CPROVER_PREFIX "isinfd" ||
3458 identifier==CPROVER_PREFIX "isinfld" ||
3459 identifier=="__builtin_isinf")
3460 {
3461 if(expr.arguments().size()!=1)
3462 {
3463 error().source_location = f_op.source_location();
3464 error() << identifier << " expects one operand" << eom;
3465 throw 0;
3466 }
3467
3469
3470 const exprt &fp_value = expr.arguments().front();
3471
3472 if(fp_value.type().id() != ID_floatbv)
3473 {
3474 error().source_location = fp_value.source_location();
3475 error() << "non-floating-point argument for " << identifier << eom;
3476 throw 0;
3477 }
3478
3479 isinf_exprt isinf_expr(expr.arguments().front());
3480 isinf_expr.add_source_location()=source_location;
3481
3483 }
3484 else if(identifier == "__builtin_isinf_sign")
3485 {
3486 if(expr.arguments().size() != 1)
3487 {
3488 error().source_location = f_op.source_location();
3489 error() << identifier << " expects one operand" << eom;
3490 throw 0;
3491 }
3492
3494
3495 // returns 1 for +inf and -1 for -inf, and 0 otherwise
3496
3497 const exprt &fp_value = expr.arguments().front();
3498
3499 if(fp_value.type().id() != ID_floatbv)
3500 {
3501 error().source_location = fp_value.source_location();
3502 error() << "non-floating-point argument for " << identifier << eom;
3503 throw 0;
3504 }
3505
3507 isinf_expr.add_source_location() = source_location;
3508
3509 return if_exprt(
3511 if_exprt(
3513 from_integer(-1, expr.type()),
3514 from_integer(1, expr.type())),
3515 from_integer(0, expr.type()));
3516 }
3517 else if(identifier == CPROVER_PREFIX "isnormalf" ||
3518 identifier == CPROVER_PREFIX "isnormald" ||
3519 identifier == CPROVER_PREFIX "isnormalld" ||
3520 identifier == "__builtin_isnormal")
3521 {
3522 if(expr.arguments().size()!=1)
3523 {
3524 error().source_location = f_op.source_location();
3525 error() << identifier << " expects one operand" << eom;
3526 throw 0;
3527 }
3528
3530
3531 const exprt &fp_value = expr.arguments()[0];
3532
3533 if(fp_value.type().id() != ID_floatbv)
3534 {
3535 error().source_location = fp_value.source_location();
3536 error() << "non-floating-point argument for " << identifier << eom;
3537 throw 0;
3538 }
3539
3540 isnormal_exprt isnormal_expr(expr.arguments().front());
3541 isnormal_expr.add_source_location()=source_location;
3542
3544 }
3545 else if(identifier==CPROVER_PREFIX "signf" ||
3546 identifier==CPROVER_PREFIX "signd" ||
3547 identifier==CPROVER_PREFIX "signld" ||
3548 identifier=="__builtin_signbit" ||
3549 identifier=="__builtin_signbitf" ||
3550 identifier=="__builtin_signbitl")
3551 {
3552 if(expr.arguments().size()!=1)
3553 {
3554 error().source_location = f_op.source_location();
3555 error() << identifier << " expects one operand" << eom;
3556 throw 0;
3557 }
3558
3560
3561 sign_exprt sign_expr(expr.arguments().front());
3562 sign_expr.add_source_location()=source_location;
3563
3565 }
3566 else if(identifier=="__builtin_popcount" ||
3567 identifier=="__builtin_popcountl" ||
3568 identifier=="__builtin_popcountll" ||
3569 identifier=="__popcnt16" ||
3570 identifier=="__popcnt" ||
3571 identifier=="__popcnt64")
3572 {
3573 if(expr.arguments().size()!=1)
3574 {
3575 error().source_location = f_op.source_location();
3576 error() << identifier << " expects one operand" << eom;
3577 throw 0;
3578 }
3579
3581
3582 popcount_exprt popcount_expr(expr.arguments().front(), expr.type());
3583 popcount_expr.add_source_location()=source_location;
3584
3585 return std::move(popcount_expr);
3586 }
3587 else if(
3588 identifier == "__builtin_clz" || identifier == "__builtin_clzl" ||
3589 identifier == "__builtin_clzll" || identifier == "__lzcnt16" ||
3590 identifier == "__lzcnt" || identifier == "__lzcnt64")
3591 {
3592 if(expr.arguments().size() != 1)
3593 {
3594 error().source_location = f_op.source_location();
3595 error() << identifier << " expects one operand" << eom;
3596 throw 0;
3597 }
3598
3600
3602 expr.arguments().front(), identifier.starts_with("__lzcnt"), expr.type()};
3603 clz.add_source_location() = source_location;
3604
3605 return std::move(clz);
3606 }
3607 else if(
3608 identifier == "__builtin_ctz" || identifier == "__builtin_ctzl" ||
3609 identifier == "__builtin_ctzll")
3610 {
3611 if(expr.arguments().size() != 1)
3612 {
3613 error().source_location = f_op.source_location();
3614 error() << identifier << " expects one operand" << eom;
3615 throw 0;
3616 }
3617
3619
3621 expr.arguments().front(), false, expr.type()};
3622 ctz.add_source_location() = source_location;
3623
3624 return std::move(ctz);
3625 }
3626 else if(
3627 identifier == "__builtin_ffs" || identifier == "__builtin_ffsl" ||
3628 identifier == "__builtin_ffsll")
3629 {
3630 if(expr.arguments().size() != 1)
3631 {
3632 error().source_location = f_op.source_location();
3633 error() << identifier << " expects one operand" << eom;
3634 throw 0;
3635 }
3636
3638
3639 find_first_set_exprt ffs{expr.arguments().front(), expr.type()};
3640 ffs.add_source_location() = source_location;
3641
3642 return std::move(ffs);
3643 }
3644 else if(identifier=="__builtin_expect")
3645 {
3646 // This is a gcc extension to provide branch prediction.
3647 // We compile it away, but adding some IR instruction for
3648 // this would clearly be an option. Note that the type
3649 // of the return value is wired to "long", i.e.,
3650 // this may trigger a type conversion due to the signature
3651 // of this function.
3652 if(expr.arguments().size()!=2)
3653 {
3654 error().source_location = f_op.source_location();
3655 error() << "__builtin_expect expects two arguments" << eom;
3656 throw 0;
3657 }
3658
3660
3661 return typecast_exprt(expr.arguments()[0], expr.type());
3662 }
3663 else if(
3664 identifier == "__builtin_object_size" ||
3665 identifier == "__builtin_dynamic_object_size")
3666 {
3667 // These are gcc extensions to provide information about
3668 // object sizes at compile time
3669 // http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
3670 // Our behavior is as if it was never possible to determine the object that
3671 // the pointer pointed to.
3672
3673 if(expr.arguments().size()!=2)
3674 {
3675 error().source_location = f_op.source_location();
3676 error() << "__builtin_object_size expects two arguments" << eom;
3677 throw 0;
3678 }
3679
3681
3682 make_constant(expr.arguments()[1]);
3683
3685
3686 if(expr.arguments()[1] == true)
3687 arg1=1;
3688 else if(expr.arguments()[1] == false)
3689 arg1=0;
3690 else if(to_integer(to_constant_expr(expr.arguments()[1]), arg1))
3691 {
3692 error().source_location = f_op.source_location();
3693 error() << "__builtin_object_size expects constant as second argument, "
3694 << "but got " << to_string(expr.arguments()[1]) << eom;
3695 throw 0;
3696 }
3697
3698 exprt tmp;
3699
3700 // the following means "don't know"
3701 if(arg1==0 || arg1==1)
3702 {
3703 tmp=from_integer(-1, size_type());
3704 tmp.add_source_location()=f_op.source_location();
3705 }
3706 else
3707 {
3709 tmp.add_source_location()=f_op.source_location();
3710 }
3711
3712 return tmp;
3713 }
3714 else if(identifier=="__builtin_choose_expr")
3715 {
3716 // this is a gcc extension similar to ?:
3717 if(expr.arguments().size()!=3)
3718 {
3719 error().source_location = f_op.source_location();
3720 error() << "__builtin_choose_expr expects three arguments" << eom;
3721 throw 0;
3722 }
3723
3725
3726 exprt arg0 =
3729
3730 if(arg0 == true)
3731 return expr.arguments()[1];
3732 else
3733 return expr.arguments()[2];
3734 }
3735 else if(identifier=="__builtin_constant_p")
3736 {
3737 // this is a gcc extension to tell whether the argument
3738 // is known to be a compile-time constant
3739 if(expr.arguments().size()!=1)
3740 {
3741 error().source_location = f_op.source_location();
3742 error() << "__builtin_constant_p expects one argument" << eom;
3743 throw 0;
3744 }
3745
3746 // do not typecheck the argument - it is never evaluated, and thus side
3747 // effects must not show up either
3748
3749 // try to produce constant
3750 exprt tmp1=expr.arguments().front();
3751 simplify(tmp1, *this);
3752
3753 bool is_constant=false;
3754
3755 // Need to do some special treatment for string literals,
3756 // which are (void *)&("lit"[0])
3757 if(
3758 tmp1.id() == ID_typecast &&
3759 to_typecast_expr(tmp1).op().id() == ID_address_of &&
3760 to_address_of_expr(to_typecast_expr(tmp1).op()).object().id() ==
3761 ID_index &&
3763 .array()
3764 .id() == ID_string_constant)
3765 {
3766 is_constant=true;
3767 }
3768 else
3769 is_constant=tmp1.is_constant();
3770
3772 tmp2.add_source_location()=source_location;
3773
3774 return tmp2;
3775 }
3776 else if(identifier=="__builtin_classify_type")
3777 {
3778 // This is a gcc/clang extension that produces an integer
3779 // constant for the type of the argument expression.
3780 if(expr.arguments().size()!=1)
3781 {
3782 error().source_location = f_op.source_location();
3783 error() << "__builtin_classify_type expects one argument" << eom;
3784 throw 0;
3785 }
3786
3788
3789 exprt object=expr.arguments()[0];
3790
3791 // The value doesn't matter at all, we only care about the type.
3792 // Need to sync with typeclass.h.
3793 // use underlying type for bit fields
3794 const typet &type = object.type().id() == ID_c_bit_field
3795 ? to_c_bit_field_type(object.type()).underlying_type()
3796 : object.type();
3797
3798 unsigned type_number;
3799
3800 if(type.id() == ID_bool || type.id() == ID_c_bool)
3801 {
3802 // clang returns 4 for _Bool, gcc treats these as 'int'.
3803 type_number =
3805 }
3806 else
3807 {
3808 type_number = type.id() == ID_empty ? 0u
3809 : (type.id() == ID_bool || type.id() == ID_c_bool) ? 4u
3810 : (type.id() == ID_pointer || type.id() == ID_array) ? 5u
3811 : type.id() == ID_floatbv ? 8u
3812 : (type.id() == ID_complex &&
3813 to_complex_type(type).subtype().id() == ID_floatbv)
3814 ? 9u
3815 : type.id() == ID_struct_tag ? 12u
3816 : type.id() == ID_union_tag
3817 ? 13u
3818 : 1u; // int, short, char, enum_tag
3819 }
3820
3822 tmp.add_source_location()=source_location;
3823
3824 return tmp;
3825 }
3826 else if(
3827 identifier == "__builtin_add_overflow" ||
3828 identifier == "__builtin_sadd_overflow" ||
3829 identifier == "__builtin_saddl_overflow" ||
3830 identifier == "__builtin_saddll_overflow" ||
3831 identifier == "__builtin_uadd_overflow" ||
3832 identifier == "__builtin_uaddl_overflow" ||
3833 identifier == "__builtin_uaddll_overflow" ||
3834 identifier == "__builtin_add_overflow_p")
3835 {
3836 return typecheck_builtin_overflow(expr, ID_plus);
3837 }
3838 else if(
3839 identifier == "__builtin_sub_overflow" ||
3840 identifier == "__builtin_ssub_overflow" ||
3841 identifier == "__builtin_ssubl_overflow" ||
3842 identifier == "__builtin_ssubll_overflow" ||
3843 identifier == "__builtin_usub_overflow" ||
3844 identifier == "__builtin_usubl_overflow" ||
3845 identifier == "__builtin_usubll_overflow" ||
3846 identifier == "__builtin_sub_overflow_p")
3847 {
3849 }
3850 else if(
3851 identifier == "__builtin_mul_overflow" ||
3852 identifier == "__builtin_smul_overflow" ||
3853 identifier == "__builtin_smull_overflow" ||
3854 identifier == "__builtin_smulll_overflow" ||
3855 identifier == "__builtin_umul_overflow" ||
3856 identifier == "__builtin_umull_overflow" ||
3857 identifier == "__builtin_umulll_overflow" ||
3858 identifier == "__builtin_mul_overflow_p")
3859 {
3860 return typecheck_builtin_overflow(expr, ID_mult);
3861 }
3862 else if(
3863 identifier == "__builtin_bitreverse8" ||
3864 identifier == "__builtin_bitreverse16" ||
3865 identifier == "__builtin_bitreverse32" ||
3866 identifier == "__builtin_bitreverse64")
3867 {
3868 // clang only
3869 if(expr.arguments().size() != 1)
3870 {
3871 std::ostringstream error_message;
3872 error_message << "error: " << identifier << " expects one operand";
3874 error_message.str(), expr.source_location()};
3875 }
3876
3878
3880 bitreverse.add_source_location() = source_location;
3881
3882 return std::move(bitreverse);
3883 }
3884 else
3885 return nil_exprt();
3886 // NOLINTNEXTLINE(readability/fn_size)
3887}
3888
3891 const irep_idt &arith_op)
3892{
3893 const irep_idt &identifier = to_symbol_expr(expr.function()).identifier();
3894
3895 // check function signature
3896 if(expr.arguments().size() != 3)
3897 {
3898 std::ostringstream error_message;
3899 error_message << identifier << " takes exactly 3 arguments, but "
3900 << expr.arguments().size() << " were provided";
3902 error_message.str(), expr.source_location()};
3903 }
3904
3906
3907 auto lhs = expr.arguments()[0];
3908 auto rhs = expr.arguments()[1];
3909 auto result = expr.arguments()[2];
3910
3911 const bool is__p_variant = has_suffix(id2string(identifier), "_p");
3912
3913 {
3914 auto const raise_wrong_argument_error =
3915 [this, identifier](
3916 const exprt &wrong_argument, std::size_t argument_number, bool _p) {
3917 std::ostringstream error_message;
3918 error_message << "error: " << identifier << " has signature "
3919 << identifier << "(integral, integral, integral"
3920 << (_p ? "" : "*") << "), "
3921 << "but argument " << argument_number << " ("
3922 << expr2c(wrong_argument, *this) << ") has type `"
3923 << type2c(wrong_argument.type(), *this) << '`';
3925 error_message.str(), wrong_argument.source_location()};
3926 };
3927 for(int arg_index = 0; arg_index <= (!is__p_variant ? 1 : 2); ++arg_index)
3928 {
3929 auto const &argument = expr.arguments()[arg_index];
3930
3932 {
3934 }
3935 }
3936 if(
3937 !is__p_variant && (result.type().id() != ID_pointer ||
3939 to_pointer_type(result.type()).base_type())))
3940 {
3942 }
3943 }
3944
3946 std::move(lhs),
3947 std::move(rhs),
3948 std::move(result),
3949 expr.source_location()};
3950}
3951
3954{
3955 const irep_idt &identifier = to_symbol_expr(expr.function()).identifier();
3956
3957 // check function signature
3958 if(expr.arguments().size() != 2)
3959 {
3960 std::ostringstream error_message;
3961 error_message << "error: " << identifier
3962 << " takes exactly two arguments, but "
3963 << expr.arguments().size() << " were provided";
3965 error_message.str(), expr.source_location()};
3966 }
3967
3968 exprt result;
3969 if(
3970 identifier == CPROVER_PREFIX "saturating_minus" ||
3971 identifier == "__builtin_elementwise_sub_sat")
3972 {
3973 result = saturating_minus_exprt{expr.arguments()[0], expr.arguments()[1]};
3974 }
3975 else if(
3976 identifier == CPROVER_PREFIX "saturating_plus" ||
3977 identifier == "__builtin_elementwise_add_sat")
3978 {
3979 result = saturating_plus_exprt{expr.arguments()[0], expr.arguments()[1]};
3980 }
3981 else
3983
3985 result.add_source_location() = expr.source_location();
3986
3987 return result;
3988}
3989
3994{
3995 const exprt &f_op=expr.function();
3996 const code_typet &code_type=to_code_type(f_op.type());
3997 exprt::operandst &arguments=expr.arguments();
3998 const code_typet::parameterst &parameters = code_type.parameters();
3999
4000 // no. of arguments test
4001
4002 if(code_type.get_bool(ID_C_incomplete))
4003 {
4004 // can't check
4005 }
4006 else if(code_type.is_KnR())
4007 {
4008 // We are generous on KnR; any number is ok.
4009 // We will fill in missing ones with "nondet".
4010 for(std::size_t i = arguments.size(); i < parameters.size(); ++i)
4011 {
4012 arguments.push_back(
4013 side_effect_expr_nondett{parameters[i].type(), expr.source_location()});
4014 }
4015 }
4016 else if(code_type.has_ellipsis())
4017 {
4018 if(parameters.size() > arguments.size())
4019 {
4021 error() << "not enough function arguments" << eom;
4022 throw 0;
4023 }
4024 }
4025 else if(parameters.size() != arguments.size())
4026 {
4028 error() << "wrong number of function arguments: "
4029 << "expected " << parameters.size() << ", but got "
4030 << arguments.size() << eom;
4031 throw 0;
4032 }
4033
4034 for(std::size_t i=0; i<arguments.size(); i++)
4035 {
4036 exprt &op=arguments[i];
4037
4038 if(op.is_nil())
4039 {
4040 // ignore
4041 }
4042 else if(i < parameters.size())
4043 {
4044 const code_typet::parametert &parameter = parameters[i];
4045
4046 if(
4047 parameter.is_boolean() && op.id() == ID_side_effect &&
4048 op.get(ID_statement) == ID_assign && op.type().id() != ID_bool)
4049 {
4051 warning() << "assignment where Boolean argument is expected" << eom;
4052 }
4053
4054 implicit_typecast(op, parameter.type());
4055 }
4056 else
4057 {
4058 // don't know type, just do standard conversion
4059
4060 if(op.type().id() == ID_array)
4061 {
4063 dest_type.base_type().set(ID_C_constant, true);
4065 }
4066 }
4067 }
4068}
4069
4071{
4072 // nothing to do
4073}
4074
4076{
4077 exprt &operand = to_unary_expr(expr).op();
4078
4079 const typet &o_type = operand.type();
4080
4081 if(o_type.id()==ID_vector)
4082 {
4083 if(is_number(to_vector_type(o_type).element_type()))
4084 {
4085 // Vector arithmetic.
4086 expr.type()=operand.type();
4087 return;
4088 }
4089 }
4090
4092
4093 if(is_number(operand.type()))
4094 {
4095 expr.type()=operand.type();
4096 return;
4097 }
4098
4100 error() << "operator '" << expr.id() << "' not defined for type '"
4101 << to_string(operand.type()) << "'" << eom;
4102 throw 0;
4103}
4104
4106{
4108
4109 // This is not quite accurate: the standard says the result
4110 // should be of type 'int'.
4111 // We do 'bool' anyway to get more compact formulae. Eventually,
4112 // this should be achieved by means of simplification, and not
4113 // in the frontend.
4114 expr.type()=bool_typet();
4115}
4116
4118 const vector_typet &type0,
4119 const vector_typet &type1)
4120{
4121 // This is relatively restrictive!
4122
4123 // compare dimension
4124 const auto s0 = numeric_cast<mp_integer>(type0.size());
4125 const auto s1 = numeric_cast<mp_integer>(type1.size());
4126 if(!s0.has_value())
4127 return false;
4128 if(!s1.has_value())
4129 return false;
4130 if(*s0 != *s1)
4131 return false;
4132
4133 // compare subtype
4134 if(
4135 (type0.element_type().id() == ID_signedbv ||
4136 type0.element_type().id() == ID_unsignedbv) &&
4137 (type1.element_type().id() == ID_signedbv ||
4138 type1.element_type().id() == ID_unsignedbv) &&
4139 to_bitvector_type(type0.element_type()).get_width() ==
4140 to_bitvector_type(type1.element_type()).get_width())
4141 return true;
4142
4143 return type0.element_type() == type1.element_type();
4144}
4145
4147{
4148 auto &binary_expr = to_binary_expr(expr);
4149 exprt &op0 = binary_expr.op0();
4150 exprt &op1 = binary_expr.op1();
4151
4152 const typet o_type0 = op0.type();
4153 const typet o_type1 = op1.type();
4154
4155 if(o_type0.id()==ID_vector &&
4156 o_type1.id()==ID_vector)
4157 {
4158 if(
4161 is_number(to_vector_type(o_type0).element_type()))
4162 {
4163 // Vector arithmetic has fairly strict typing rules, no promotion
4164 op1 = typecast_exprt::conditional_cast(op1, op0.type());
4165 expr.type()=op0.type();
4166 return;
4167 }
4168 }
4169 else if(
4170 o_type0.id() == ID_vector && o_type1.id() != ID_vector &&
4172 {
4173 // convert op1 to the vector type
4174 op1 = typecast_exprt(op1, o_type0);
4175 expr.type() = o_type0;
4176 return;
4177 }
4178 else if(
4179 o_type0.id() != ID_vector && o_type1.id() == ID_vector &&
4181 {
4182 // convert op0 to the vector type
4183 op0 = typecast_exprt(op0, o_type1);
4184 expr.type() = o_type1;
4185 return;
4186 }
4187
4188 if(expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
4189 {
4191 }
4192 else
4193 {
4194 // promote!
4196 }
4197
4198 const typet &type0 = op0.type();
4199 const typet &type1 = op1.type();
4200
4201 if(expr.id()==ID_plus || expr.id()==ID_minus ||
4202 expr.id()==ID_mult || expr.id()==ID_div)
4203 {
4204 if(type0.id()==ID_pointer || type1.id()==ID_pointer)
4205 {
4207 return;
4208 }
4209 else if(type0==type1)
4210 {
4211 if(is_number(type0))
4212 {
4213 expr.type()=type0;
4214 return;
4215 }
4216 }
4217 }
4218 else if(expr.id()==ID_mod)
4219 {
4220 if(type0==type1)
4221 {
4222 if(type0.id()==ID_signedbv || type0.id()==ID_unsignedbv)
4223 {
4224 expr.type()=type0;
4225 return;
4226 }
4227 }
4228 }
4229 else if(
4230 expr.id() == ID_bitand || expr.id() == ID_bitnand ||
4231 expr.id() == ID_bitxor || expr.id() == ID_bitor)
4232 {
4233 if(type0==type1)
4234 {
4235 if(is_number(type0))
4236 {
4237 expr.type()=type0;
4238 return;
4239 }
4240 else if(type0.id()==ID_bool)
4241 {
4242 if(expr.id()==ID_bitand)
4243 expr.id(ID_and);
4244 else if(expr.id() == ID_bitnand)
4245 expr.id(ID_nand);
4246 else if(expr.id()==ID_bitor)
4247 expr.id(ID_or);
4248 else if(expr.id()==ID_bitxor)
4249 expr.id(ID_xor);
4250 else
4252 expr.type()=type0;
4253 return;
4254 }
4255 }
4256 }
4257 else if(expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
4258 {
4259 if(
4260 type0 == type1 &&
4261 (type0.id() == ID_signedbv || type0.id() == ID_unsignedbv))
4262 {
4263 expr.type() = type0;
4264 return;
4265 }
4266 }
4267
4269 error() << "operator '" << expr.id() << "' not defined for types '"
4270 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4271 << eom;
4272 throw 0;
4273}
4274
4276{
4277 PRECONDITION(expr.id() == ID_shl || expr.id() == ID_shr);
4278
4279 exprt &op0=expr.op0();
4280 exprt &op1=expr.op1();
4281
4282 const typet o_type0 = op0.type();
4283 const typet o_type1 = op1.type();
4284
4285 if(o_type0.id()==ID_vector &&
4286 o_type1.id()==ID_vector)
4287 {
4288 if(
4289 to_vector_type(o_type0).element_type() ==
4290 to_vector_type(o_type1).element_type() &&
4291 is_number(to_vector_type(o_type0).element_type()))
4292 {
4293 // {a0, a1, ..., an} >> {b0, b1, ..., bn} ==
4294 // {a0 >> b0, a1 >> b1, ..., an >> bn}
4295 // Fairly strict typing rules, no promotion
4296 expr.type()=op0.type();
4297 return;
4298 }
4299 }
4300
4301 if(
4302 o_type0.id() == ID_vector &&
4303 is_number(to_vector_type(o_type0).element_type()) && is_number(o_type1))
4304 {
4305 // {a0, a1, ..., an} >> b == {a0 >> b, a1 >> b, ..., an >> b}
4306 op1 = typecast_exprt(op1, o_type0);
4307 expr.type()=op0.type();
4308 return;
4309 }
4310
4311 // must do the promotions _separately_!
4314
4315 if(is_number(op0.type()) &&
4316 is_number(op1.type()))
4317 {
4318 expr.type()=op0.type();
4319
4320 if(expr.id()==ID_shr) // shifting operation depends on types
4321 {
4322 const typet &op0_type = op0.type();
4323
4324 if(op0_type.id()==ID_unsignedbv)
4325 {
4326 expr.id(ID_lshr);
4327 return;
4328 }
4329 else if(op0_type.id()==ID_signedbv)
4330 {
4331 expr.id(ID_ashr);
4332 return;
4333 }
4334 }
4335
4336 return;
4337 }
4338
4340 error() << "operator '" << expr.id() << "' not defined for types '"
4341 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4342 << eom;
4343 throw 0;
4344}
4345
4347{
4348 const typet &type=expr.type();
4349 PRECONDITION(type.id() == ID_pointer);
4350
4351 const typet &base_type = to_pointer_type(type).base_type();
4352
4353 if(
4354 base_type.id() == ID_struct_tag &&
4355 follow_tag(to_struct_tag_type(base_type)).is_incomplete())
4356 {
4358 error() << "pointer arithmetic with unknown object size" << eom;
4359 throw 0;
4360 }
4361 else if(
4362 base_type.id() == ID_union_tag &&
4363 follow_tag(to_union_tag_type(base_type)).is_incomplete())
4364 {
4366 error() << "pointer arithmetic with unknown object size" << eom;
4367 throw 0;
4368 }
4369 else if(
4370 base_type.id() == ID_empty &&
4372 {
4374 error() << "pointer arithmetic with unknown object size" << eom;
4375 throw 0;
4376 }
4377 else if(base_type.id() == ID_empty)
4378 {
4379 // This is a gcc extension.
4380 // https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.html
4382 expr.swap(tc);
4383 }
4384}
4385
4387{
4388 auto &binary_expr = to_binary_expr(expr);
4389 exprt &op0 = binary_expr.op0();
4390 exprt &op1 = binary_expr.op1();
4391
4392 const typet &type0 = op0.type();
4393 const typet &type1 = op1.type();
4394
4395 if(expr.id()==ID_minus ||
4396 (expr.id()==ID_side_effect && expr.get(ID_statement)==ID_assign_minus))
4397 {
4398 if(type0.id()==ID_pointer &&
4399 type1.id()==ID_pointer)
4400 {
4401 if(type0 != type1)
4402 {
4404 "pointer subtraction over different types", expr.source_location()};
4405 }
4406 expr.type()=pointer_diff_type();
4409 return;
4410 }
4411
4412 if(type0.id()==ID_pointer &&
4413 (type1.id()==ID_bool ||
4414 type1.id()==ID_c_bool ||
4415 type1.id()==ID_unsignedbv ||
4416 type1.id()==ID_signedbv ||
4417 type1.id()==ID_c_bit_field ||
4418 type1.id()==ID_c_enum_tag))
4419 {
4421 make_index_type(op1);
4422 expr.type() = op0.type();
4423 return;
4424 }
4425 }
4426 else if(expr.id()==ID_plus ||
4427 (expr.id()==ID_side_effect && expr.get(ID_statement)==ID_assign_plus))
4428 {
4429 exprt *p_op, *int_op;
4430
4431 if(type0.id()==ID_pointer)
4432 {
4433 p_op=&op0;
4434 int_op=&op1;
4435 }
4436 else if(type1.id()==ID_pointer)
4437 {
4438 p_op=&op1;
4439 int_op=&op0;
4440 }
4441 else
4442 {
4443 p_op=int_op=nullptr;
4445 }
4446
4447 const typet &int_op_type = int_op->type();
4448
4449 if(int_op_type.id()==ID_bool ||
4450 int_op_type.id()==ID_c_bool ||
4451 int_op_type.id()==ID_unsignedbv ||
4452 int_op_type.id()==ID_signedbv ||
4455 {
4458 expr.type()=p_op->type();
4459 return;
4460 }
4461 }
4462
4463 irep_idt op_name;
4464
4465 if(expr.id()==ID_side_effect)
4466 op_name=to_side_effect_expr(expr).get_statement();
4467 else
4468 op_name=expr.id();
4469
4471 error() << "operator '" << op_name << "' not defined for types '"
4472 << to_string(type0) << "' and '" << to_string(type1) << "'" << eom;
4473 throw 0;
4474}
4475
4477{
4478 auto &binary_expr = to_binary_expr(expr);
4481
4482 // This is not quite accurate: the standard says the result
4483 // should be of type 'int'.
4484 // We do 'bool' anyway to get more compact formulae. Eventually,
4485 // this should be achieved by means of simplification, and not
4486 // in the frontend.
4487 expr.type()=bool_typet();
4488}
4489
4491 side_effect_exprt &expr)
4492{
4493 const irep_idt &statement=expr.get_statement();
4494
4495 auto &binary_expr = to_binary_expr(expr);
4496 exprt &op0 = binary_expr.op0();
4497 exprt &op1 = binary_expr.op1();
4498
4499 {
4500 const typet &type0=op0.type();
4501
4502 if(type0.id()==ID_empty)
4503 {
4505 error() << "cannot assign void" << eom;
4506 throw 0;
4507 }
4508
4509 if(!op0.get_bool(ID_C_lvalue))
4510 {
4512 error() << "assignment error: '" << to_string(op0) << "' not an lvalue"
4513 << eom;
4514 throw 0;
4515 }
4516
4517 if(type0.get_bool(ID_C_constant))
4518 {
4520 error() << "'" << to_string(op0) << "' is constant" << eom;
4521 throw 0;
4522 }
4523
4524 // refuse to assign arrays
4525 if(type0.id() == ID_array)
4526 {
4528 error() << "direct assignments to arrays not permitted" << eom;
4529 throw 0;
4530 }
4531 }
4532
4533 // Add a cast to the underlying type for bit fields.
4534 if(op0.type() != op1.type() && op0.type().id() == ID_c_bit_field)
4535 {
4536 op1 =
4537 typecast_exprt{op1, to_c_bit_field_type(op0.type()).underlying_type()};
4538 }
4539
4540 const typet o_type0=op0.type();
4541 const typet o_type1=op1.type();
4542
4543 expr.type()=o_type0;
4544
4545 if(statement==ID_assign)
4546 {
4548 return;
4549 }
4550 else if(statement==ID_assign_shl ||
4551 statement==ID_assign_shr)
4552 {
4553 if(o_type0.id() == ID_vector)
4554 {
4556
4557 if(
4558 o_type1.id() == ID_vector &&
4559 vector_o_type0.element_type() ==
4560 to_vector_type(o_type1).element_type() &&
4561 is_number(vector_o_type0.element_type()))
4562 {
4563 return;
4564 }
4565 else if(is_number(vector_o_type0.element_type()) && is_number(o_type1))
4566 {
4567 op1 = typecast_exprt(op1, o_type0);
4568 return;
4569 }
4570 }
4571
4574
4575 if(is_number(op0.type()) && is_number(op1.type()))
4576 {
4577 if(statement==ID_assign_shl)
4578 {
4579 return;
4580 }
4581 else // assign_shr
4582 {
4583 // distinguish arithmetic from logical shifts by looking at type
4584
4585 typet underlying_type=op0.type();
4586
4587 if(underlying_type.id()==ID_unsignedbv ||
4588 underlying_type.id()==ID_c_bool)
4589 {
4591 return;
4592 }
4593 else if(underlying_type.id()==ID_signedbv)
4594 {
4596 return;
4597 }
4598 }
4599 }
4600 }
4601 else if(statement==ID_assign_bitxor ||
4602 statement==ID_assign_bitand ||
4603 statement==ID_assign_bitor)
4604 {
4605 // these are more restrictive
4606 if(o_type0.id()==ID_bool ||
4607 o_type0.id()==ID_c_bool)
4608 {
4610 if(
4611 op1.is_boolean() || op1.type().id() == ID_c_bool ||
4612 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4613 op1.type().id() == ID_signedbv || op1.type().id() == ID_c_bit_field)
4614 {
4615 return;
4616 }
4617 }
4618 else if(o_type0.id()==ID_c_enum_tag ||
4619 o_type0.id()==ID_unsignedbv ||
4620 o_type0.id()==ID_signedbv ||
4621 o_type0.id()==ID_c_bit_field)
4622 {
4624 if(
4625 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4626 op1.type().id() == ID_signedbv || op1.type().id() == ID_c_bit_field)
4627 {
4628 return;
4629 }
4630 }
4631 else if(o_type0.id()==ID_vector &&
4632 o_type1.id()==ID_vector)
4633 {
4634 // We are willing to do a modest amount of conversion
4637 {
4639 return;
4640 }
4641 }
4642 else if(
4643 o_type0.id() == ID_vector &&
4644 (o_type1.id() == ID_bool || o_type1.id() == ID_c_bool ||
4645 o_type1.id() == ID_c_enum_tag || o_type1.id() == ID_unsignedbv ||
4646 o_type1.id() == ID_signedbv))
4647 {
4649 op1 = typecast_exprt(op1, o_type0);
4650 return;
4651 }
4652 }
4653 else
4654 {
4655 if(o_type0.id()==ID_pointer &&
4656 (statement==ID_assign_minus || statement==ID_assign_plus))
4657 {
4659 return;
4660 }
4661 else if(o_type0.id()==ID_vector &&
4662 o_type1.id()==ID_vector)
4663 {
4664 // We are willing to do a modest amount of conversion
4667 {
4669 return;
4670 }
4671 }
4672 else if(o_type0.id() == ID_vector)
4673 {
4675
4676 if(
4677 is_number(op1.type()) || op1.is_boolean() ||
4678 op1.type().id() == ID_c_bool || op1.type().id() == ID_c_enum_tag)
4679 {
4680 op1 = typecast_exprt(op1, o_type0);
4681 return;
4682 }
4683 }
4684 else if(o_type0.id()==ID_bool ||
4685 o_type0.id()==ID_c_bool)
4686 {
4688 if(
4689 op1.is_boolean() || op1.type().id() == ID_c_bool ||
4690 op1.type().id() == ID_c_enum_tag || op1.type().id() == ID_unsignedbv ||
4691 op1.type().id() == ID_signedbv)
4692 {
4693 return;
4694 }
4695 }
4696 else
4697 {
4699
4700 if(
4701 is_number(op1.type()) || op1.is_boolean() ||
4702 op1.type().id() == ID_c_bool || op1.type().id() == ID_c_enum_tag)
4703 {
4704 return;
4705 }
4706 }
4707 }
4708
4710 error() << "assignment '" << statement << "' not defined for types '"
4711 << to_string(o_type0) << "' and '" << to_string(o_type1) << "'"
4712 << eom;
4713
4714 throw 0;
4715}
4716
4721{
4722public:
4724 {
4725 }
4726
4728 bool operator()(const exprt &e) const
4729 {
4730 return is_constant(e);
4731 }
4732
4733protected:
4735
4738 bool is_constant(const exprt &e) const
4739 {
4740 if(e.id() == ID_infinity)
4741 return true;
4742
4743 if(e.is_constant())
4744 return true;
4745
4746 if(e.id() == ID_address_of)
4747 {
4748 return is_constant_address_of(to_address_of_expr(e).object());
4749 }
4750 else if(
4751 e.id() == ID_typecast || e.id() == ID_array_of || e.id() == ID_plus ||
4752 e.id() == ID_mult || e.id() == ID_array || e.id() == ID_with ||
4753 e.id() == ID_struct || e.id() == ID_union || e.id() == ID_empty_union ||
4754 e.id() == ID_equal || e.id() == ID_notequal || e.id() == ID_lt ||
4755 e.id() == ID_le || e.id() == ID_gt || e.id() == ID_ge ||
4756 e.id() == ID_if || e.id() == ID_not || e.id() == ID_and ||
4757 e.id() == ID_or || e.id() == ID_bitnot || e.id() == ID_bitand ||
4758 e.id() == ID_bitor || e.id() == ID_bitxor || e.id() == ID_vector)
4759 {
4760 return std::all_of(
4761 e.operands().begin(), e.operands().end(), [this](const exprt &op) {
4762 return is_constant(op);
4763 });
4764 }
4765
4766 return false;
4767 }
4768
4770 bool is_constant_address_of(const exprt &e) const
4771 {
4772 if(e.id() == ID_symbol)
4773 {
4774 return e.type().id() == ID_code ||
4775 ns.lookup(to_symbol_expr(e).identifier()).is_static_lifetime;
4776 }
4777 else if(e.id() == ID_array && e.get_bool(ID_C_string_constant))
4778 return true;
4779 else if(e.id() == ID_label)
4780 return true;
4781 else if(e.id() == ID_index)
4782 {
4784
4785 return is_constant_address_of(index_expr.array()) &&
4786 is_constant(index_expr.index());
4787 }
4788 else if(e.id() == ID_member)
4789 {
4790 return is_constant_address_of(to_member_expr(e).compound());
4791 }
4792 else if(e.id() == ID_dereference)
4793 {
4795
4796 return is_constant(deref.pointer());
4797 }
4798 else if(e.id() == ID_string_constant)
4799 return true;
4800
4801 return false;
4802 }
4803};
4804
4806{
4807 source_locationt location = expr.find_source_location();
4808
4809 // Floating-point expressions may require a rounding mode.
4810 // ISO 9899:1999 F.7.2 says that the default is "round to nearest".
4811 // Some compilers have command-line options to override.
4812 const auto rounding_mode =
4814 adjust_float_expressions(expr, rounding_mode);
4815
4816 simplify(expr, *this);
4817 expr.add_source_location() = location;
4818
4819 if(!is_compile_time_constantt(*this)(expr))
4820 {
4821 error().source_location = location;
4822 error() << "expected constant expression, but got '" << to_string(expr)
4823 << "'" << eom;
4824 throw 0;
4825 }
4826}
4827
4829{
4830 source_locationt location = expr.find_source_location();
4831 make_constant(expr);
4832 make_index_type(expr);
4833 simplify(expr, *this);
4834 expr.add_source_location() = location;
4835
4836 if(!is_compile_time_constantt(*this)(expr))
4837 {
4838 error().source_location = location;
4839 error() << "conversion to integer constant failed" << eom;
4840 throw 0;
4841 }
4842}
4843
4845 const exprt &expr,
4846 const irep_idt &id,
4847 const std::string &message) const
4848{
4849 if(!has_subexpr(expr, id))
4850 return;
4851
4853 error() << message << eom;
4854 throw 0;
4855}
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:440
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:649
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:737
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:784
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:1957
Real part of the expression describing a complex number.
Definition std_expr.h:1920
Complex numbers made of pair of given subtype.
Definition std_types.h:1074
struct configt::ansi_ct ansi_c
A constant literal expression.
Definition std_expr.h:3007
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:1339
Base class for all expressions.
Definition expr.h:57
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition expr.cpp:68
std::vector< exprt > operandst
Definition expr.h:59
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition expr.h:164
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:3135
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:2426
Array index operator.
Definition std_expr.h:1431
An expression denoting infinity.
Definition std_expr.h:3160
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:1104
A base class for multi-ary expressions Associativity is not specified.
Definition std_expr.h:908
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:3144
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:1006
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:557
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:612
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:3126
Type with multiple subtypes.
Definition type.h:222
Semantic type conversion.
Definition std_expr.h:1995
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2003
The type of an expression, extends irept.
Definition type.h:29
Generic base class for unary expressions.
Definition std_expr.h:364
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:1724
The vector type.
Definition std_types.h:1005
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:828
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1494
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2024
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:721
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:424
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2501
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:2953
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3078
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:221
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition std_types.h:1057
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:1099
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