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