cprover
Loading...
Searching...
No Matches
cpp_typecheck_expr.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: C++ Language Type Checking
4
5Author: Daniel Kroening, kroening@cs.cmu.edu
6
7\*******************************************************************/
8
11
12#include "cpp_typecheck.h"
13
14#ifdef DEBUG
15#include <iostream>
16#endif
17
18#include <util/arith_tools.h>
19#include <util/c_types.h>
20#include <util/config.h>
23#include <util/pointer_expr.h>
26
27#include <ansi-c/c_qualifiers.h>
28
29#include "cpp_exception_id.h"
30#include "cpp_type2name.h"
31#include "cpp_typecheck_fargs.h"
32#include "cpp_util.h"
33#include "expr2cpp.h"
34
36 const symbolt &symb,
37 const irep_idt &base_name,
38 irep_idt &identifier)
39{
40 for(const auto &b : to_struct_type(symb.type).bases())
41 {
42 const irep_idt &id = b.type().get_identifier();
43 if(lookup(id).base_name == base_name)
44 {
45 identifier = id;
46 return true;
47 }
48 }
49
50 return false;
51}
52
55{
56 if(expr.id()==ID_cpp_name)
58 else if(expr.id()=="cpp-this")
60 else if(expr.id() == ID_pointer_to_member)
61 convert_pmop(expr);
62 else if(expr.id() == ID_new_object)
63 {
64 }
65 else if(operator_is_overloaded(expr))
66 {
67 }
68 else if(expr.id()=="explicit-typecast")
70 else if(expr.id()=="explicit-constructor-call")
72 else if(expr.id()==ID_code)
73 {
74#ifdef DEBUG
75 std::cerr << "E: " << expr.pretty() << '\n';
76 std::cerr << "cpp_typecheckt::typecheck_expr_main got code\n";
77#endif
79 }
80 else if(expr.id()==ID_symbol)
81 {
82 // ignore here
83#ifdef DEBUG
84 std::cerr << "E: " << expr.pretty() << '\n';
85 std::cerr << "cpp_typecheckt::typecheck_expr_main got symbol\n";
86#endif
87 }
88 else if(expr.id()=="__is_base_of")
89 {
90 // an MS extension
91 // http://msdn.microsoft.com/en-us/library/ms177194(v=vs.80).aspx
92
93 typet base=static_cast<const typet &>(expr.find("type_arg1"));
94 typet deriv=static_cast<const typet &>(expr.find("type_arg2"));
95
96 typecheck_type(base);
97 typecheck_type(deriv);
98
99 base = follow(base);
100 deriv = follow(deriv);
101
102 if(base.id()!=ID_struct || deriv.id()!=ID_struct)
103 expr=false_exprt();
104 else
105 {
106 irep_idt base_name=base.get(ID_name);
107 const class_typet &class_type=to_class_type(deriv);
108
109 if(class_type.has_base(base_name))
110 expr=true_exprt();
111 else
112 expr=false_exprt();
113 }
114 }
115 else if(expr.id()==ID_msc_uuidof)
116 {
117 // these appear to have type "struct _GUID"
118 // and they are lvalues!
119 expr.type() = struct_tag_typet("tag-_GUID");
120 expr.set(ID_C_lvalue, true);
121 }
122 else if(expr.id()==ID_noexcept)
123 {
124 // TODO
125 expr=false_exprt();
126 }
127 else if(expr.id()==ID_initializer_list)
128 {
129 expr.type().id(ID_initializer_list);
130 }
131 else
133}
134
136{
137 PRECONDITION(expr.operands().size() == 3);
138
140
141 if(expr.op1().type().id()==ID_empty ||
142 expr.op1().type().id()==ID_empty)
143 {
144 if(expr.op1().get_bool(ID_C_lvalue))
145 {
146 exprt e1(expr.op1());
148 {
150 error() << "error: lvalue to rvalue conversion" << eom;
151 throw 0;
152 }
153 }
154
155 if(expr.op1().type().id()==ID_array)
156 {
157 exprt e1(expr.op1());
159 {
161 error() << "error: array to pointer conversion" << eom;
162 throw 0;
163 }
164 }
165
166 if(expr.op1().type().id()==ID_code)
167 {
168 exprt e1(expr.op1());
170 {
172 error() << "error: function to pointer conversion" << eom;
173 throw 0;
174 }
175 }
176
177 if(expr.op2().get_bool(ID_C_lvalue))
178 {
179 exprt e2(expr.op2());
181 {
183 error() << "error: lvalue to rvalue conversion" << eom;
184 throw 0;
185 }
186 }
187
188 if(expr.op2().type().id()==ID_array)
189 {
190 exprt e2(expr.op2());
192 {
194 error() << "error: array to pointer conversion" << eom;
195 throw 0;
196 }
197 }
198
199 if(expr.op2().type().id()==ID_code)
200 {
201 exprt e2(expr.op2());
203 {
205 error() << "error: function to pointer conversion" << eom;
206 throw 0;
207 }
208 }
209
210 if(expr.op1().get(ID_statement)==ID_throw &&
211 expr.op2().get(ID_statement)!=ID_throw)
212 expr.type()=expr.op2().type();
213 else if(expr.op2().get(ID_statement)==ID_throw &&
214 expr.op1().get(ID_statement)!=ID_throw)
215 expr.type()=expr.op1().type();
216 else if(expr.op1().type().id()==ID_empty &&
217 expr.op2().type().id()==ID_empty)
218 expr.type() = void_type();
219 else
220 {
222 error() << "error: bad types for operands" << eom;
223 throw 0;
224 }
225 return;
226 }
227
228 if(expr.op1().type() == expr.op2().type())
229 {
230 c_qualifierst qual1, qual2;
231 qual1.read(expr.op1().type());
232 qual2.read(expr.op2().type());
233
234 if(qual1.is_subset_of(qual2))
235 expr.type()=expr.op1().type();
236 else
237 expr.type()=expr.op2().type();
238 }
239 else
240 {
241 exprt e1=expr.op1();
242 exprt e2=expr.op2();
243
244 if(implicit_conversion_sequence(expr.op1(), expr.op2().type(), e1))
245 {
246 expr.type()=e1.type();
247 expr.op1().swap(e1);
248 }
249 else if(implicit_conversion_sequence(expr.op2(), expr.op1().type(), e2))
250 {
251 expr.type()=e2.type();
252 expr.op2().swap(e2);
253 }
254 else if(
255 expr.op1().type().id() == ID_array &&
256 expr.op2().type().id() == ID_array &&
257 to_array_type(expr.op1().type()).element_type() ==
259 {
260 // array-to-pointer conversion
261
262 index_exprt index1(expr.op1(), from_integer(0, c_index_type()));
263
264 index_exprt index2(expr.op2(), from_integer(0, c_index_type()));
265
266 address_of_exprt addr1(index1);
267 address_of_exprt addr2(index2);
268
269 expr.op1()=addr1;
270 expr.op2()=addr2;
271 expr.type()=addr1.type();
272 return;
273 }
274 else
275 {
277 error() << "error: types are incompatible.\n"
278 << "I got '" << type2cpp(expr.op1().type(), *this) << "' and '"
279 << type2cpp(expr.op2().type(), *this) << "'." << eom;
280 throw 0;
281 }
282 }
283
284 if(expr.op1().get_bool(ID_C_lvalue) &&
285 expr.op2().get_bool(ID_C_lvalue))
286 expr.set(ID_C_lvalue, true);
287
288 return;
289}
290
297
299{
300 // We need to overload, "sizeof-expression" can be mis-parsed
301 // as a type.
302
303 if(expr.operands().empty())
304 {
305 const typet &type=
306 static_cast<const typet &>(expr.find(ID_type_arg));
307
308 if(type.id()==ID_cpp_name)
309 {
310 // sizeof(X) may be ambiguous -- X can be either a type or
311 // an expression.
312
314
315 exprt symbol_expr=resolve(
316 to_cpp_name(static_cast<const irept &>(type)),
318 fargs);
319
320 if(symbol_expr.id()!=ID_type)
321 {
322 expr.copy_to_operands(symbol_expr);
323 expr.remove(ID_type_arg);
324 }
325 }
326 else if(type.id()==ID_array)
327 {
328 // sizeof(expr[index]) can be parsed as an array type!
329
330 if(to_array_type(type).element_type().id() == ID_cpp_name)
331 {
333
334 exprt symbol_expr = resolve(
336 static_cast<const irept &>(to_array_type(type).element_type())),
338 fargs);
339
340 if(symbol_expr.id()!=ID_type)
341 {
342 // _NOT_ a type
343 index_exprt index_expr(symbol_expr, to_array_type(type).size());
344 expr.copy_to_operands(index_expr);
345 expr.remove(ID_type_arg);
346 }
347 }
348 }
349 }
350
352}
353
358
360 exprt &expr,
361 const cpp_typecheck_fargst &fargs)
362{
363 if(expr.id()==ID_cpp_name)
364 typecheck_expr_cpp_name(expr, fargs);
365 else if(expr.id()==ID_member)
366 {
368 typecheck_expr_member(expr, fargs);
369 }
370 else if(expr.id()==ID_ptrmember)
371 {
374
375 // is operator-> overloaded?
376 if(to_unary_expr(expr).op().type().id() != ID_pointer)
377 {
378 std::string op_name="operator->";
379
380 // turn this into a function call
381 // first do function/operator
382 const cpp_namet cpp_name(op_name, expr.source_location());
383
385 cpp_name.as_expr(),
386 {to_unary_expr(expr).op()},
388 expr.source_location());
389 function_call.arguments().reserve(expr.operands().size());
390
392
394
395 to_unary_expr(expr).op().swap(function_call);
396 typecheck_function_expr(expr, fargs);
397 return;
398 }
399
400 typecheck_expr_ptrmember(expr, fargs);
401 }
402 else
403 typecheck_expr(expr);
404}
405
407{
408 // at least one argument must have class or enumerated type
409
410 for(const auto &op : expr.operands())
411 {
412 typet t = op.type();
413
414 if(is_reference(t))
416
417 if(
418 t.id() == ID_struct || t.id() == ID_union || t.id() == ID_c_enum ||
419 t.id() == ID_c_enum_tag || t.id() == ID_struct_tag ||
420 t.id() == ID_union_tag)
421 {
422 return true;
423 }
424 }
425
426 return false;
427}
428
430{
432 const char *op_name;
433} const operators[] =
434{
435 { ID_plus, "+" },
436 { ID_minus, "-" },
437 { ID_mult, "*" },
438 { ID_div, "/" },
439 { ID_bitnot, "~" },
440 { ID_bitand, "&" },
441 { ID_bitor, "|" },
442 { ID_bitxor, "^" },
443 { ID_not, "!" },
444 { ID_unary_minus, "-" },
445 { ID_and, "&&" },
446 { ID_or, "||" },
447 { ID_not, "!" },
448 { ID_index, "[]" },
449 { ID_equal, "==" },
450 { ID_lt, "<"},
451 { ID_le, "<="},
452 { ID_gt, ">"},
453 { ID_ge, ">="},
454 { ID_shl, "<<"},
455 { ID_shr, ">>"},
456 { ID_notequal, "!=" },
457 { ID_dereference, "*" },
458 { ID_ptrmember, "->" },
459 { irep_idt(), nullptr }
461
463{
464 // Check argument types first.
465 // At least one struct/enum operand is required.
466
467 if(!overloadable(expr))
468 return false;
469 else if(expr.id()==ID_dereference &&
470 expr.get_bool(ID_C_implicit))
471 return false;
472
473 PRECONDITION(expr.operands().size() >= 1);
474
475 if(expr.id()=="explicit-typecast")
476 {
477 // the cast operator can be overloaded
478
479 typet t=expr.type();
481 std::string op_name=std::string("operator")+"("+cpp_type2name(t)+")";
482
483 // turn this into a function call
484 const cpp_namet cpp_name(op_name, expr.source_location());
485
486 // See if the struct declares the cast operator as a member
487 bool found_in_struct=false;
488 PRECONDITION(!expr.operands().empty());
489 typet t0(follow(to_unary_expr(expr).op().type()));
490
491 if(t0.id()==ID_struct)
492 {
493 for(const auto &c : to_struct_type(t0).components())
494 {
495 if(!c.get_bool(ID_from_base) && c.get_base_name() == op_name)
496 {
497 found_in_struct=true;
498 break;
499 }
500 }
501 }
502
503 if(!found_in_struct)
504 return false;
505
506 exprt member(ID_member);
507 member.add(ID_component_cpp_name) = cpp_name;
508
509 member.copy_to_operands(
511
513 std::move(member), {}, uninitialized_typet{}, expr.source_location());
514 function_call.arguments().reserve(expr.operands().size());
515
516 if(expr.operands().size()>1)
517 {
518 for(exprt::operandst::const_iterator
519 it=(expr.operands().begin()+1);
520 it!=(expr).operands().end();
521 it++)
522 function_call.arguments().push_back(*it);
523 }
524
526
527 if(expr.id()==ID_ptrmember)
528 {
529 add_implicit_dereference(function_call);
531 to_unary_expr(expr).op().swap(function_call);
532 typecheck_expr(expr);
533 return true;
534 }
535
536 expr.swap(function_call);
537 return true;
538 }
539
540 for(const operator_entryt *e=operators;
541 !e->id.empty();
542 e++)
543 {
544 if(expr.id()==e->id)
545 {
547 expr.id() != ID_dereference || !expr.get_bool(ID_C_implicit),
548 "no implicit dereference");
549
550 std::string op_name=std::string("operator")+e->op_name;
551
552 // first do function/operator
553 const cpp_namet cpp_name(op_name, expr.source_location());
554
555 // turn this into a function call
556 // There are two options to overload an operator:
557 //
558 // 1. In the scope of a as a.operator(b, ...)
559 // 2. Anywhere in scope as operator(a, b, ...)
560 //
561 // Using both is not allowed.
562 //
563 // We try and fail silently, maybe conversions will work
564 // instead.
565
566 // TODO: need to resolve an incomplete struct (template) here
567 // go into scope of first operand
568 if(
569 to_multi_ary_expr(expr).op0().type().id() == ID_struct_tag &&
570 follow(to_multi_ary_expr(expr).op0().type()).id() == ID_struct)
571 {
572 const irep_idt &struct_identifier =
573 to_multi_ary_expr(expr).op0().type().get(ID_identifier);
574
575 // get that scope
576 cpp_save_scopet save_scope(cpp_scopes);
577 cpp_scopes.set_scope(struct_identifier);
578
579 // build fargs for resolver
581 fargs.operands=expr.operands();
582 fargs.has_object=true;
583 fargs.in_use=true;
584
585 // should really be a qualified search
586 exprt resolve_result=resolve(
587 cpp_name, cpp_typecheck_resolvet::wantt::VAR, fargs, false);
588
589 if(resolve_result.is_not_nil())
590 {
591 // Found! We turn op(a, b, ...) into a.op(b, ...)
592 exprt member(ID_member);
593 member.add(ID_component_cpp_name) = cpp_name;
594
595 member.copy_to_operands(
597
599 std::move(member),
600 {},
602 expr.source_location());
603 function_call.arguments().reserve(expr.operands().size());
604
605 if(expr.operands().size()>1)
606 {
607 // skip first
608 for(exprt::operandst::const_iterator
609 it=expr.operands().begin()+1;
610 it!=expr.operands().end();
611 it++)
612 function_call.arguments().push_back(*it);
613 }
614
616
617 expr=function_call;
618
619 return true;
620 }
621 }
622
623 // 2nd option!
624 {
626 fargs.operands=expr.operands();
627 fargs.has_object=false;
628 fargs.in_use=true;
629
630 exprt resolve_result=resolve(
631 cpp_name, cpp_typecheck_resolvet::wantt::VAR, fargs, false);
632
633 if(resolve_result.is_not_nil())
634 {
635 // found!
637 cpp_name.as_expr(),
638 {},
640 expr.source_location());
641 function_call.arguments().reserve(expr.operands().size());
642
643 // now do arguments
644 for(const auto &op : as_const(expr).operands())
645 function_call.arguments().push_back(op);
646
648
649 if(expr.id()==ID_ptrmember)
650 {
651 add_implicit_dereference(function_call);
653 to_multi_ary_expr(expr).op0() = function_call;
654 typecheck_expr(expr);
655 return true;
656 }
657
658 expr=function_call;
659
660 return true;
661 }
662 }
663 }
664 }
665
666 return false;
667}
668
670{
671 if(expr.operands().size()!=1)
672 {
674 error() << "address_of expects one operand" << eom;
675 throw 0;
676 }
677
678 exprt &op = to_address_of_expr(expr).op();
679
680 if(!op.get_bool(ID_C_lvalue) && expr.type().id()==ID_code)
681 {
683 error() << "expr not an lvalue" << eom;
684 throw 0;
685 }
686
687 if(op.type().id() == ID_code)
688 {
689 // we take the address of the method.
690 DATA_INVARIANT(op.id() == ID_member, "address-of code must be a member");
691 exprt symb = cpp_symbol_expr(lookup(op.get(ID_component_name)));
692 address_of_exprt address(symb, pointer_type(symb.type()));
693 address.set(ID_C_implicit, true);
694 op.swap(address);
695 }
696
697 if(op.id() == ID_address_of && op.get_bool(ID_C_implicit))
698 {
699 // must be the address of a function
700 code_typet &code_type =
702
703 code_typet::parameterst &args=code_type.parameters();
704 if(!args.empty() && args.front().get_this())
705 {
706 // it's a pointer to member function
707 const struct_tag_typet symbol(code_type.get(ID_C_member_name));
708 op.type().add(ID_to_member) = symbol;
709
710 if(code_type.get_bool(ID_C_is_virtual))
711 {
713 error() << "error: pointers to virtual methods"
714 << " are currently not implemented" << eom;
715 throw 0;
716 }
717 }
718 }
719 else if(op.id() == ID_ptrmember && to_unary_expr(op).op().id() == "cpp-this")
720 {
721 expr.type() = pointer_type(op.type());
722 expr.type().add(ID_to_member) =
723 to_pointer_type(to_unary_expr(op).op().type()).base_type();
724 return;
725 }
726
727 // the C front end does not know about references
728 const bool is_ref=is_reference(expr.type());
730 if(is_ref)
732}
733
735{
736 expr.type() = void_type();
737
738 PRECONDITION(expr.operands().size() == 1 || expr.operands().empty());
739
740 if(expr.operands().size()==1)
741 {
742 // nothing really to do; one can throw _almost_ anything
743 const typet &exception_type = to_unary_expr(expr).op().type();
744
745 if(exception_type.id() == ID_empty)
746 {
748 error() << "cannot throw void" << eom;
749 throw 0;
750 }
751
752 // annotate the relevant exception IDs
753 expr.set(ID_exception_list,
754 cpp_exception_list(exception_type, *this));
755 }
756}
757
759{
760 // next, find out if we do an array
761
762 if(expr.type().id()==ID_array)
763 {
764 // first typecheck the element type
766
767 // typecheck the size
768 exprt &size=to_array_type(expr.type()).size();
769 typecheck_expr(size);
770
771 bool size_is_unsigned=(size.type().id()==ID_unsignedbv);
772 bitvector_typet integer_type(
773 size_is_unsigned ? ID_unsignedbv : ID_signedbv, config.ansi_c.int_width);
774 implicit_typecast(size, integer_type);
775
776 expr.set(ID_statement, ID_cpp_new_array);
777
778 // save the size expression
779 expr.set(ID_size, to_array_type(expr.type()).size());
780
781 // new actually returns a pointer, not an array
782 pointer_typet ptr_type =
784 expr.type().swap(ptr_type);
785 }
786 else
787 {
788 // first typecheck type
789 typecheck_type(expr.type());
790
791 expr.set(ID_statement, ID_cpp_new);
792
793 pointer_typet ptr_type=pointer_type(expr.type());
794 expr.type().swap(ptr_type);
795 }
796
797 exprt object_expr(ID_new_object, to_pointer_type(expr.type()).base_type());
798 object_expr.set(ID_C_lvalue, true);
799
801
802 // not yet typechecked-stuff
803 exprt &initializer=static_cast<exprt &>(expr.add(ID_initializer));
804
805 // arrays must not have an initializer
806 if(!initializer.operands().empty() &&
807 expr.get(ID_statement)==ID_cpp_new_array)
808 {
811 error() << "new with array type must not use initializer" << eom;
812 throw 0;
813 }
814
815 auto code = cpp_constructor(
816 expr.find_source_location(), object_expr, initializer.operands());
817
818 if(code.has_value())
819 expr.add(ID_initializer).swap(code.value());
820 else
821 expr.add(ID_initializer) = nil_exprt();
822
823 // we add the size of the object for convenience of the
824 // runtime library
825 auto size_of_opt =
826 size_of_expr(to_pointer_type(expr.type()).base_type(), *this);
827
828 if(size_of_opt.has_value())
829 {
830 auto &sizeof_expr = static_cast<exprt &>(expr.add(ID_sizeof));
831 sizeof_expr = size_of_opt.value();
832 sizeof_expr.add(ID_C_c_sizeof_type) =
834 }
835}
836
838{
839 exprt result;
840
841 if(src.id()==ID_comma)
842 {
843 PRECONDITION(src.operands().size() == 2);
844 result = collect_comma_expression(to_binary_expr(src).op0());
845 result.copy_to_operands(to_binary_expr(src).op1());
846 }
847 else
848 result.copy_to_operands(src);
849
850 return result;
851}
852
854{
855 // these can have 0 or 1 arguments
856
857 if(expr.operands().empty())
858 {
859 // Default value, e.g., int()
860 typecheck_type(expr.type());
861 auto new_expr =
862 ::zero_initializer(expr.type(), expr.find_source_location(), *this);
863 if(!new_expr.has_value())
864 {
866 error() << "cannot zero-initialize '" << to_string(expr.type()) << "'"
867 << eom;
868 throw 0;
869 }
870
871 new_expr->add_source_location() = expr.source_location();
872 expr = *new_expr;
873 }
874 else if(expr.operands().size()==1)
875 {
876 auto &op = to_unary_expr(expr).op();
877
878 // Explicitly given value, e.g., int(1).
879 // There is an expr-vs-type ambiguity, as it is possible to write
880 // (f)(1), where 'f' is a function symbol and not a type.
881 // This also exists with a "comma expression", e.g.,
882 // (f)(1, 2, 3)
883
884 if(expr.type().id()==ID_cpp_name)
885 {
886 // try to resolve as type
888
889 exprt symbol_expr=resolve(
890 to_cpp_name(static_cast<const irept &>(expr.type())),
892 fargs,
893 false); // fail silently
894
895 if(symbol_expr.id()==ID_type)
896 expr.type()=symbol_expr.type();
897 else
898 {
899 // It's really a function call. Note that multiple arguments
900 // become a comma expression, and that these are already typechecked.
902 static_cast<const exprt &>(static_cast<const irept &>(expr.type())),
903 collect_comma_expression(op).operands(),
905 expr.source_location());
906
908
909 expr.swap(f_call);
910 return;
911 }
912 }
913 else
914 typecheck_type(expr.type());
915
916 // We allow (TYPE){ initializer_list }
917 // This is called "compound literal", and is syntactic
918 // sugar for a (possibly local) declaration.
919 if(op.id() == ID_initializer_list)
920 {
921 // just do a normal initialization
922 do_initializer(op, expr.type(), false);
923
924 // This produces a struct-expression,
925 // union-expression, array-expression,
926 // or an expression for a pointer or scalar.
927 // We produce a compound_literal expression.
928 exprt tmp(ID_compound_literal, expr.type());
929 tmp.add_to_operands(std::move(op));
930 expr=tmp;
931 expr.set(ID_C_lvalue, true); // these are l-values
932 return;
933 }
934
935 exprt new_expr;
936
937 if(
938 const_typecast(op, expr.type(), new_expr) ||
939 static_typecast(op, expr.type(), new_expr, false) ||
940 reinterpret_typecast(op, expr.type(), new_expr, false))
941 {
942 expr=new_expr;
944 }
945 else
946 {
948 error() << "invalid explicit cast:\n"
949 << "operand type: '" << to_string(op.type()) << "'\n"
950 << "casting to: '" << to_string(expr.type()) << "'" << eom;
951 throw 0;
952 }
953 }
954 else
955 {
957 error() << "explicit typecast expects 0 or 1 operands" << eom;
958 throw 0;
959 }
960}
961
963{
964 typecheck_type(expr.type());
965
966 if(cpp_is_pod(expr.type()))
967 {
968 expr.id("explicit-typecast");
970 }
971 else
972 {
973 CHECK_RETURN(expr.type().id() == ID_struct);
974
975 struct_tag_typet tag(expr.type().get(ID_name));
977
978 exprt e=expr;
979 new_temporary(e.source_location(), tag, e.operands(), expr);
980 }
981}
982
984{
986 {
988 error() << "`this' is not allowed here" << eom;
989 throw 0;
990 }
991
992 const exprt &this_expr=cpp_scopes.current_scope().this_expr;
993 const source_locationt source_location=expr.find_source_location();
994
995 PRECONDITION(this_expr.is_not_nil());
996 PRECONDITION(this_expr.type().id() == ID_pointer);
997
998 expr=this_expr;
999 expr.add_source_location()=source_location;
1000}
1001
1003{
1004 if(expr.operands().size()!=1)
1005 {
1007 error() << "delete expects one operand" << eom;
1008 throw 0;
1009 }
1010
1011 const irep_idt statement=expr.get(ID_statement);
1012
1013 if(statement==ID_cpp_delete)
1014 {
1015 }
1016 else if(statement==ID_cpp_delete_array)
1017 {
1018 }
1019 else
1021
1023
1024 if(pointer_type.id()!=ID_pointer)
1025 {
1027 error() << "delete takes a pointer type operand, but got '"
1028 << to_string(pointer_type) << "'" << eom;
1029 throw 0;
1030 }
1031
1032 // remove any const-ness of the argument
1033 // (which would impair the call to the destructor)
1034 to_pointer_type(pointer_type).base_type().remove(ID_C_constant);
1035
1036 // delete expressions are always void
1037 expr.type()=typet(ID_empty);
1038
1039 // we provide the right destructor, for the convenience
1040 // of later stages
1041 exprt new_object(ID_new_object, to_pointer_type(pointer_type).base_type());
1042 new_object.add_source_location()=expr.source_location();
1043 new_object.set(ID_C_lvalue, true);
1044
1046
1047 auto destructor_code = cpp_destructor(expr.source_location(), new_object);
1048
1049 if(destructor_code.has_value())
1050 {
1051 // this isn't typechecked yet
1052 typecheck_code(destructor_code.value());
1053 expr.set(ID_destructor, destructor_code.value());
1054 }
1055 else
1056 expr.set(ID_destructor, nil_exprt());
1057}
1058
1060{
1061 // should not be called
1062 #if 0
1063 std::cout << "E: " << expr.pretty() << '\n';
1065 #endif
1066}
1067
1069 exprt &expr,
1070 const cpp_typecheck_fargst &fargs)
1071{
1072 if(expr.operands().size()!=1)
1073 {
1075 error() << "error: member operator expects one operand" << eom;
1076 throw 0;
1077 }
1078
1079 exprt &op0 = to_unary_expr(expr).op();
1081
1082 // The notation for explicit calls to destructors can be used regardless
1083 // of whether the type defines a destructor. This allows you to make such
1084 // explicit calls without knowing if a destructor is defined for the type.
1085 // An explicit call to a destructor where none is defined has no effect.
1086
1087 if(
1088 expr.find(ID_component_cpp_name).is_not_nil() &&
1089 to_cpp_name(expr.find(ID_component_cpp_name)).is_destructor() &&
1090 op0.type().id() != ID_struct && op0.type().id() != ID_struct_tag)
1091 {
1092 exprt tmp(ID_cpp_dummy_destructor);
1094 expr.swap(tmp);
1095 return;
1096 }
1097
1098 // The member operator will trigger template elaboration
1100
1101 const typet &followed_op0_type=follow(op0.type());
1102
1103 if(followed_op0_type.id()!=ID_struct &&
1104 followed_op0_type.id()!=ID_union)
1105 {
1107 error() << "error: member operator requires struct/union type "
1108 << "on left hand side but got '" << to_string(followed_op0_type)
1109 << "'" << eom;
1110 throw 0;
1111 }
1112
1113 const struct_union_typet &type=
1114 to_struct_union_type(followed_op0_type);
1115
1116 if(type.is_incomplete())
1117 {
1119 error() << "error: member operator got incomplete type "
1120 << "on left hand side" << eom;
1121 throw 0;
1122 }
1123
1124 irep_idt struct_identifier=type.get(ID_name);
1125
1126 if(expr.find(ID_component_cpp_name).is_not_nil())
1127 {
1128 cpp_namet component_cpp_name=
1129 to_cpp_name(expr.find(ID_component_cpp_name));
1130
1131 // go to the scope of the struct/union
1132 cpp_save_scopet save_scope(cpp_scopes);
1133 cpp_scopes.set_scope(struct_identifier);
1134
1135 // resolve the member name in this scope
1136 cpp_typecheck_fargst new_fargs(fargs);
1137 new_fargs.add_object(op0);
1138
1139 exprt symbol_expr=resolve(
1140 component_cpp_name,
1142 new_fargs);
1143
1144 if(symbol_expr.id()==ID_dereference)
1145 {
1146 CHECK_RETURN(symbol_expr.get_bool(ID_C_implicit));
1147 exprt tmp = to_dereference_expr(symbol_expr).pointer();
1148 symbol_expr.swap(tmp);
1149 }
1150
1152 symbol_expr.id() == ID_symbol || symbol_expr.id() == ID_member ||
1153 symbol_expr.is_constant(),
1154 "expression kind unexpected");
1155
1156 // If it is a symbol or a constant, just return it!
1157 // Note: the resolver returns a symbol if the member
1158 // is static or if it is a constructor.
1159
1160 if(symbol_expr.id()==ID_symbol)
1161 {
1162 if(
1163 symbol_expr.type().id() == ID_code &&
1164 to_code_type(symbol_expr.type()).return_type().id() == ID_constructor)
1165 {
1167 error() << "error: member '"
1168 << lookup(symbol_expr.get(ID_identifier)).base_name
1169 << "' is a constructor" << eom;
1170 throw 0;
1171 }
1172 else
1173 {
1174 // it must be a static component
1175 const struct_typet::componentt &pcomp =
1176 type.get_component(to_symbol_expr(symbol_expr).get_identifier());
1177
1178 if(pcomp.is_nil())
1179 {
1181 error() << "error: '" << symbol_expr.get(ID_identifier)
1182 << "' is not static member "
1183 << "of class '" << to_string(op0.type()) << "'" << eom;
1184 throw 0;
1185 }
1186 }
1187
1188 expr=symbol_expr;
1189 return;
1190 }
1191 else if(symbol_expr.is_constant())
1192 {
1193 expr=symbol_expr;
1194 return;
1195 }
1196
1197 const irep_idt component_name=symbol_expr.get(ID_component_name);
1198
1199 expr.remove(ID_component_cpp_name);
1200 expr.set(ID_component_name, component_name);
1201 }
1202
1203 const irep_idt &component_name=expr.get(ID_component_name);
1204 INVARIANT(!component_name.empty(), "component name should not be empty");
1205
1208
1210 op0.type().id() == ID_struct || op0.type().id() == ID_union ||
1211 op0.type().id() == ID_struct_tag || op0.type().id() == ID_union_tag);
1212
1213 exprt member;
1214
1215 if(get_component(expr.source_location(), op0, component_name, member))
1216 {
1217 // because of possible anonymous members
1218 expr.swap(member);
1219 }
1220 else
1221 {
1223 error() << "error: member '" << component_name << "' of '"
1224 << to_string(type) << "' not found" << eom;
1225 throw 0;
1226 }
1227
1229
1230 if(expr.type().id()==ID_code)
1231 {
1232 // Check if the function body has to be typechecked
1233 symbolt &component_symbol = symbol_table.get_writeable_ref(component_name);
1234
1235 if(component_symbol.value.id() == ID_cpp_not_typechecked)
1236 component_symbol.value.set(ID_is_used, true);
1237 }
1238}
1239
1241 exprt &expr,
1242 const cpp_typecheck_fargst &fargs)
1243{
1244 PRECONDITION(expr.id() == ID_ptrmember);
1245
1246 if(expr.operands().size()!=1)
1247 {
1249 error() << "error: ptrmember operator expects one operand" << eom;
1250 throw 0;
1251 }
1252
1253 auto &op = to_unary_expr(expr).op();
1254
1256
1257 if(op.type().id() != ID_pointer)
1258 {
1260 error() << "error: ptrmember operator requires pointer type "
1261 << "on left hand side, but got '" << to_string(op.type()) << "'"
1262 << eom;
1263 throw 0;
1264 }
1265
1266 exprt tmp;
1267 op.swap(tmp);
1268
1269 op.id(ID_dereference);
1270 op.add_to_operands(std::move(tmp));
1271 op.add_source_location()=expr.source_location();
1273
1274 expr.id(ID_member);
1275 typecheck_expr_member(expr, fargs);
1276}
1277
1279{
1282
1283 if(e.arguments().size() != 1)
1284 {
1286 error() << "cast expressions expect one operand" << eom;
1287 throw 0;
1288 }
1289
1290 exprt &f_op=e.function();
1291 exprt &cast_op=e.arguments().front();
1292
1293 add_implicit_dereference(cast_op);
1294
1295 const irep_idt &id=
1296 f_op.get_sub().front().get(ID_identifier);
1297
1298 if(f_op.get_sub().size()!=2 ||
1299 f_op.get_sub()[1].id()!=ID_template_args)
1300 {
1302 error() << id << " expects template argument" << eom;
1303 throw 0;
1304 }
1305
1306 irept &template_arguments=f_op.get_sub()[1].add(ID_arguments);
1307
1308 if(template_arguments.get_sub().size()!=1)
1309 {
1311 error() << id << " expects one template argument" << eom;
1312 throw 0;
1313 }
1314
1315 irept &template_arg=template_arguments.get_sub().front();
1316
1317 if(template_arg.id() != ID_type && template_arg.id() != ID_ambiguous)
1318 {
1320 error() << id << " expects a type as template argument" << eom;
1321 throw 0;
1322 }
1323
1324 typet &type=static_cast<typet &>(
1325 template_arguments.get_sub().front().add(ID_type));
1326
1327 typecheck_type(type);
1328
1329 source_locationt source_location=expr.source_location();
1330
1331 exprt new_expr;
1332 if(id==ID_const_cast)
1333 {
1334 if(!const_typecast(cast_op, type, new_expr))
1335 {
1337 error() << "type mismatch on const_cast:\n"
1338 << "operand type: '" << to_string(cast_op.type()) << "'\n"
1339 << "cast type: '" << to_string(type) << "'" << eom;
1340 throw 0;
1341 }
1342 }
1343 else if(id==ID_dynamic_cast)
1344 {
1345 if(!dynamic_typecast(cast_op, type, new_expr))
1346 {
1348 error() << "type mismatch on dynamic_cast:\n"
1349 << "operand type: '" << to_string(cast_op.type()) << "'\n"
1350 << "cast type: '" << to_string(type) << "'" << eom;
1351 throw 0;
1352 }
1353 }
1354 else if(id==ID_reinterpret_cast)
1355 {
1356 if(!reinterpret_typecast(cast_op, type, new_expr))
1357 {
1359 error() << "type mismatch on reinterpret_cast:\n"
1360 << "operand type: '" << to_string(cast_op.type()) << "'\n"
1361 << "cast type: '" << to_string(type) << "'" << eom;
1362 throw 0;
1363 }
1364 }
1365 else if(id==ID_static_cast)
1366 {
1367 if(!static_typecast(cast_op, type, new_expr))
1368 {
1370 error() << "type mismatch on static_cast:\n"
1371 << "operand type: '" << to_string(cast_op.type()) << "'\n"
1372 << "cast type: '" << to_string(type) << "'" << eom;
1373 throw 0;
1374 }
1375 }
1376 else
1378
1379 expr.swap(new_expr);
1380}
1381
1383 exprt &expr,
1384 const cpp_typecheck_fargst &fargs)
1385{
1386 source_locationt source_location=
1388
1389 if(expr.get_sub().size()==1 &&
1390 expr.get_sub()[0].id()==ID_name)
1391 {
1392 const irep_idt identifier=expr.get_sub()[0].get(ID_identifier);
1393
1394 if(
1395 auto gcc_polymorphic = typecheck_gcc_polymorphic_builtin(
1396 identifier, fargs.operands, source_location))
1397 {
1398 expr = std::move(*gcc_polymorphic);
1399 return;
1400 }
1401 }
1402
1403 for(std::size_t i=0; i<expr.get_sub().size(); i++)
1404 {
1405 if(expr.get_sub()[i].id()==ID_cpp_name)
1406 {
1407 typet &type=static_cast<typet &>(expr.get_sub()[i]);
1408 typecheck_type(type);
1409
1410 std::string tmp="("+cpp_type2name(type)+")";
1411
1412 typet name(ID_name);
1413 name.set(ID_identifier, tmp);
1414 name.add_source_location()=source_location;
1415
1416 type=name;
1417 }
1418 }
1419
1420 if(expr.get_sub().size()>=1 &&
1421 expr.get_sub().front().id()==ID_name)
1422 {
1423 const irep_idt &id=expr.get_sub().front().get(ID_identifier);
1424
1425 if(id==ID_const_cast ||
1426 id==ID_dynamic_cast ||
1427 id==ID_reinterpret_cast ||
1428 id==ID_static_cast)
1429 {
1430 expr.id(ID_cast_expression);
1431 return;
1432 }
1433 }
1434
1435 exprt symbol_expr=
1436 resolve(
1437 to_cpp_name(expr),
1439 fargs);
1440
1441 // we want VAR
1442 CHECK_RETURN(symbol_expr.id() != ID_type);
1443
1444 if(symbol_expr.id()==ID_member)
1445 {
1446 if(
1447 symbol_expr.operands().empty() ||
1448 to_multi_ary_expr(symbol_expr).op0().is_nil())
1449 {
1450 if(to_code_type(symbol_expr.type()).return_type().id() != ID_constructor)
1451 {
1453 {
1454 if(symbol_expr.type().id()!=ID_code)
1455 {
1456 error().source_location=source_location;
1457 error() << "object missing" << eom;
1458 throw 0;
1459 }
1460
1461 // may still be good for address of
1462 }
1463 else
1464 {
1465 // Try again
1466 exprt ptrmem(ID_ptrmember);
1467 ptrmem.operands().push_back(
1469
1470 ptrmem.add(ID_component_cpp_name)=expr;
1471
1472 ptrmem.add_source_location()=source_location;
1473 typecheck_expr_ptrmember(ptrmem, fargs);
1474 symbol_expr.swap(ptrmem);
1475 }
1476 }
1477 }
1478 }
1479
1480 symbol_expr.add_source_location()=source_location;
1481 expr=symbol_expr;
1482
1483 if(expr.id()==ID_symbol)
1485
1487}
1488
1490{
1491 if(is_reference(expr.type()))
1492 {
1493 // add implicit dereference
1494 dereference_exprt tmp(expr);
1495 tmp.set(ID_C_implicit, true);
1497 tmp.set(ID_C_lvalue, true);
1498 expr.swap(tmp);
1499 }
1500}
1501
1504{
1505 // For virtual functions, it is important to check whether
1506 // the function name is qualified. If it is qualified, then
1507 // the call is not virtual.
1508 bool is_qualified=false;
1509
1510 if(expr.function().id()==ID_member ||
1511 expr.function().id()==ID_ptrmember)
1512 {
1513 if(expr.function().get(ID_component_cpp_name)==ID_cpp_name)
1514 {
1515 const cpp_namet &cpp_name=
1516 to_cpp_name(expr.function().find(ID_component_cpp_name));
1517 is_qualified=cpp_name.is_qualified();
1518 }
1519 }
1520 else if(expr.function().id()==ID_cpp_name)
1521 {
1522 const cpp_namet &cpp_name=to_cpp_name(expr.function());
1523 is_qualified=cpp_name.is_qualified();
1524 }
1525
1526 // Backup of the original operand
1527 exprt op0=expr.function();
1528
1529 // now do the function -- this has been postponed
1531
1532 if(expr.function().id() == ID_pod_constructor)
1533 {
1534 PRECONDITION(expr.function().type().id() == ID_code);
1535
1536 // This must be a POD.
1537 const typet &pod=to_code_type(expr.function().type()).return_type();
1539
1540 // These aren't really function calls, but either conversions or
1541 // initializations.
1542 if(expr.arguments().size() <= 1)
1543 {
1544 exprt typecast("explicit-typecast");
1545 typecast.type()=pod;
1546 typecast.add_source_location()=expr.source_location();
1547 if(!expr.arguments().empty())
1548 typecast.copy_to_operands(expr.arguments().front());
1550 expr.swap(typecast);
1551 }
1552 else
1553 {
1555 error() << "zero or one argument expected" << eom;
1556 throw 0;
1557 }
1558
1559 return;
1560 }
1561 else if(expr.function().id() == ID_cast_expression)
1562 {
1563 // These are not really function calls,
1564 // but usually just type adjustments.
1565 typecheck_cast_expr(expr);
1567 return;
1568 }
1569 else if(expr.function().id() == ID_cpp_dummy_destructor)
1570 {
1571 // these don't do anything, e.g., (char*)->~char()
1573 expr.swap(no_op);
1574 return;
1575 }
1576
1577 // look at type of function
1578
1579 expr.function().type() = follow(expr.function().type());
1580
1581 if(expr.function().type().id()==ID_pointer)
1582 {
1583 if(expr.function().type().find(ID_to_member).is_not_nil())
1584 {
1585 const exprt &bound =
1586 static_cast<const exprt &>(expr.function().type().find(ID_C_bound));
1587
1588 if(bound.is_nil())
1589 {
1591 error() << "pointer-to-member not bound" << eom;
1592 throw 0;
1593 }
1594
1595 // add `this'
1596 DATA_INVARIANT(bound.type().id() == ID_pointer, "should be pointer");
1597 expr.arguments().insert(expr.arguments().begin(), bound);
1598
1599 // we don't need the object any more
1600 expr.function().type().remove(ID_C_bound);
1601 }
1602
1603 // do implicit dereference
1604 if(expr.function().id() == ID_address_of)
1605 {
1606 exprt tmp;
1607 tmp.swap(to_address_of_expr(expr.function()).object());
1608 expr.function().swap(tmp);
1609 }
1610 else
1611 {
1612 PRECONDITION(expr.function().type().id() == ID_pointer);
1613 dereference_exprt tmp(expr.function());
1615 expr.function().swap(tmp);
1616 }
1617
1618 if(expr.function().type().id()!=ID_code)
1619 {
1621 error() << "expecting code as argument" << eom;
1622 throw 0;
1623 }
1624 }
1625 else if(expr.function().type().id()==ID_code)
1626 {
1627 if(expr.function().type().get_bool(ID_C_is_virtual) && !is_qualified)
1628 {
1629 exprt vtptr_member;
1630 if(op0.id()==ID_member || op0.id()==ID_ptrmember)
1631 {
1632 vtptr_member.id(op0.id());
1633 vtptr_member.add_to_operands(std::move(to_unary_expr(op0).op()));
1634 }
1635 else
1636 {
1637 vtptr_member.id(ID_ptrmember);
1638 exprt this_expr("cpp-this");
1639 vtptr_member.add_to_operands(std::move(this_expr));
1640 }
1641
1642 // get the virtual table
1643 auto this_type = to_pointer_type(
1644 to_code_type(expr.function().type()).parameters().front().type());
1645 irep_idt vtable_name =
1646 this_type.base_type().get_string(ID_identifier) + "::@vtable_pointer";
1647
1648 const struct_typet &vt_struct =
1649 to_struct_type(follow(this_type.base_type()));
1650
1651 const struct_typet::componentt &vt_compo=
1652 vt_struct.get_component(vtable_name);
1653
1654 CHECK_RETURN(vt_compo.is_not_nil());
1655
1656 vtptr_member.set(ID_component_name, vtable_name);
1657
1658 // look for the right entry
1659 irep_idt vtentry_component_name =
1660 to_pointer_type(vt_compo.type()).base_type().get_string(ID_identifier) +
1661 "::" + expr.function().type().get_string(ID_C_virtual_name);
1662
1663 exprt vtentry_member(ID_ptrmember);
1664 vtentry_member.copy_to_operands(vtptr_member);
1665 vtentry_member.set(ID_component_name, vtentry_component_name);
1666 typecheck_expr(vtentry_member);
1667
1668 CHECK_RETURN(vtentry_member.type().id() == ID_pointer);
1669
1670 {
1671 dereference_exprt tmp(vtentry_member);
1673 vtentry_member.swap(tmp);
1674 }
1675
1676 // Typecheck the expression as if it was not virtual
1677 // (add the this pointer)
1678
1679 expr.type()=
1681
1683
1684 // Let's make the call virtual
1685 expr.function().swap(vtentry_member);
1686
1689 return;
1690 }
1691 }
1692 else if(expr.function().type().id()==ID_struct)
1693 {
1694 const cpp_namet cppname("operator()", expr.source_location());
1695
1696 exprt member(ID_member);
1697 member.add(ID_component_cpp_name)=cppname;
1698
1699 member.add_to_operands(std::move(op0));
1700
1701 expr.function().swap(member);
1703
1704 return;
1705 }
1706 else
1707 {
1709 error() << "function call expects function or function "
1710 << "pointer as argument, but got '"
1711 << to_string(expr.function().type()) << "'" << eom;
1712 throw 0;
1713 }
1714
1715 expr.type()=
1717
1718 if(expr.type().id()==ID_constructor)
1719 {
1720 PRECONDITION(expr.function().id() == ID_symbol);
1721
1722 const code_typet::parameterst &parameters=
1724
1725 DATA_INVARIANT(!parameters.empty(), "parameters expected");
1726
1727 const auto &this_type = to_pointer_type(parameters[0].type());
1728
1729 // change type from 'constructor' to object type
1730 expr.type() = this_type.base_type();
1731
1732 // create temporary object
1733 side_effect_exprt tmp_object_expr(
1734 ID_temporary_object, this_type.base_type(), expr.source_location());
1735 tmp_object_expr.set(ID_C_lvalue, true);
1736 tmp_object_expr.set(ID_mode, ID_cpp);
1737
1738 exprt member;
1739
1740 exprt new_object(ID_new_object, tmp_object_expr.type());
1741 new_object.set(ID_C_lvalue, true);
1742
1743 PRECONDITION(tmp_object_expr.type().id() == ID_struct_tag);
1744
1746 new_object,
1747 expr.function().get(ID_identifier),
1748 member);
1749
1750 // special case for the initialization of parents
1751 if(member.get_bool(ID_C_not_accessible))
1752 {
1753 PRECONDITION(!member.get(ID_C_access).empty());
1754 tmp_object_expr.set(ID_C_not_accessible, true);
1755 tmp_object_expr.set(ID_C_access, member.get(ID_C_access));
1756 }
1757
1758 // the constructor is being used, so make sure the destructor
1759 // will be available
1760 {
1761 // find name of destructor
1762 const struct_typet::componentst &components=
1763 to_struct_type(follow(tmp_object_expr.type())).components();
1764
1765 for(const auto &c : components)
1766 {
1767 const typet &type = c.type();
1768
1769 if(
1770 !c.get_bool(ID_from_base) && type.id() == ID_code &&
1771 to_code_type(type).return_type().id() == ID_destructor)
1772 {
1774 break;
1775 }
1776 }
1777 }
1778
1779 expr.function().swap(member);
1780
1783
1784 const code_expressiont new_code(expr);
1785 tmp_object_expr.add(ID_initializer)=new_code;
1786 expr.swap(tmp_object_expr);
1787 return;
1788 }
1789
1790 PRECONDITION(expr.operands().size() == 2);
1791
1792 if(expr.function().id()==ID_member)
1794 else
1795 {
1796 // for the object of a method call,
1797 // we are willing to add an "address_of"
1798 // for the sake of operator overloading
1799
1800 const code_typet::parameterst &parameters =
1802
1803 if(
1804 !parameters.empty() && parameters.front().get_this() &&
1805 !expr.arguments().empty())
1806 {
1807 const code_typet::parametert &parameter = parameters.front();
1808
1809 exprt &operand = expr.arguments().front();
1810 INVARIANT(
1811 parameter.type().id() == ID_pointer,
1812 "`this' parameter should be a pointer");
1813
1814 if(
1815 operand.type().id() != ID_pointer &&
1816 operand.type() == to_pointer_type(parameter.type()).base_type())
1817 {
1818 address_of_exprt tmp(operand, pointer_type(operand.type()));
1819 tmp.add_source_location()=operand.source_location();
1820 operand=tmp;
1821 }
1822 }
1823 }
1824
1825 CHECK_RETURN(expr.operands().size() == 2);
1826
1828
1829 CHECK_RETURN(expr.operands().size() == 2);
1830
1832
1833 // we will deal with some 'special' functions here
1834 exprt tmp=do_special_functions(expr);
1835 if(tmp.is_not_nil())
1836 expr.swap(tmp);
1837}
1838
1842{
1843 exprt &f_op=expr.function();
1844 const code_typet &code_type=to_code_type(f_op.type());
1845 const code_typet::parameterst &parameters=code_type.parameters();
1846
1847 // do default arguments
1848
1849 if(parameters.size()>expr.arguments().size())
1850 {
1851 std::size_t i=expr.arguments().size();
1852
1853 for(; i<parameters.size(); i++)
1854 {
1855 if(!parameters[i].has_default_value())
1856 break;
1857
1858 const exprt &value=parameters[i].default_value();
1859 expr.arguments().push_back(value);
1860 }
1861 }
1862
1863 exprt::operandst::iterator arg_it=expr.arguments().begin();
1864 for(const auto &parameter : parameters)
1865 {
1866 if(parameter.get_bool(ID_C_call_by_value))
1867 {
1868 DATA_INVARIANT(is_reference(parameter.type()), "reference expected");
1869
1870 if(arg_it->id()!=ID_temporary_object)
1871 {
1872 // create a temporary for the parameter
1873
1874 exprt temporary;
1876 arg_it->source_location(),
1877 to_reference_type(parameter.type()).base_type(),
1879 temporary);
1880 arg_it->swap(temporary);
1881 }
1882 }
1883
1884 ++arg_it;
1885 }
1886
1888}
1889
1891 side_effect_exprt &expr)
1892{
1893 const irep_idt &statement=expr.get(ID_statement);
1894
1895 if(statement==ID_cpp_new ||
1896 statement==ID_cpp_new_array)
1897 {
1898 typecheck_expr_new(expr);
1899 }
1900 else if(statement==ID_cpp_delete ||
1901 statement==ID_cpp_delete_array)
1902 {
1904 }
1905 else if(statement==ID_preincrement ||
1906 statement==ID_predecrement ||
1907 statement==ID_postincrement ||
1908 statement==ID_postdecrement)
1909 {
1911 }
1912 else if(statement==ID_throw)
1913 {
1915 }
1916 else if(statement==ID_temporary_object)
1917 {
1918 // TODO
1919 }
1920 else
1922}
1923
1926{
1927 PRECONDITION(expr.operands().size() == 2);
1928
1929 PRECONDITION(expr.function().id() == ID_member);
1930 PRECONDITION(expr.function().operands().size() == 1);
1931
1932 // turn e.f(...) into xx::f(e, ...)
1933
1934 exprt member_expr;
1935 member_expr.swap(expr.function());
1936
1937 symbolt &method_symbol =
1938 symbol_table.get_writeable_ref(member_expr.get(ID_component_name));
1939 const symbolt &tag_symbol = lookup(method_symbol.type.get(ID_C_member_name));
1940
1941 // build the right template map
1942 // if this is an instantiated template class method
1943 if(tag_symbol.type.find(ID_C_template)!=irept())
1944 {
1946 const irept &template_type = tag_symbol.type.find(ID_C_template);
1947 const irept &template_args = tag_symbol.type.find(ID_C_template_arguments);
1949 static_cast<const template_typet &>(template_type),
1950 static_cast<const cpp_template_args_tct &>(template_args));
1951 add_method_body(&method_symbol);
1952#ifdef DEBUG
1953 std::cout << "MAP for " << method_symbol << ":\n";
1954 template_map.print(std::cout);
1955#endif
1956 }
1957 else
1958 add_method_body(&method_symbol);
1959
1960 // build new function expression
1961 exprt new_function(cpp_symbol_expr(method_symbol));
1962 new_function.add_source_location()=member_expr.source_location();
1963 expr.function().swap(new_function);
1964
1965 if(!expr.function().type().get_bool(ID_C_is_static))
1966 {
1967 const code_typet &func_type = to_code_type(method_symbol.type);
1968 typet this_type=func_type.parameters().front().type();
1969
1970 // Special case. Make it a reference.
1971 DATA_INVARIANT(this_type.id() == ID_pointer, "this should be pointer");
1972 this_type.set(ID_C_reference, true);
1973 this_type.set(ID_C_this, true);
1974
1975 if(expr.arguments().size()==func_type.parameters().size())
1976 {
1977 // this might be set up for base-class initialisation
1978 if(
1979 expr.arguments().front().type() !=
1980 func_type.parameters().front().type())
1981 {
1982 implicit_typecast(expr.arguments().front(), this_type);
1984 is_reference(expr.arguments().front().type()),
1985 "argument should be reference");
1986 expr.arguments().front().type().remove(ID_C_reference);
1987 }
1988 }
1989 else
1990 {
1991 exprt this_arg = to_member_expr(member_expr).compound();
1992 implicit_typecast(this_arg, this_type);
1994 is_reference(this_arg.type()), "argument should be reference");
1995 this_arg.type().remove(ID_C_reference);
1996 expr.arguments().insert(expr.arguments().begin(), this_arg);
1997 }
1998 }
1999
2000 if(
2001 method_symbol.value.id() == ID_cpp_not_typechecked &&
2002 !method_symbol.value.get_bool(ID_is_used))
2003 {
2004 method_symbol.value.set(ID_is_used, true);
2005 }
2006}
2007
2009{
2010 if(expr.operands().size()!=2)
2011 {
2013 error() << "assignment side effect expected to have two operands"
2014 << eom;
2015 throw 0;
2016 }
2017
2018 typet type0 = to_binary_expr(expr).op0().type();
2019
2020 if(is_reference(type0))
2021 type0 = to_reference_type(type0).base_type();
2022
2023 if(cpp_is_pod(type0))
2024 {
2025 // for structs we use the 'implicit assignment operator',
2026 // and therefore, it is allowed to assign to a rvalue struct.
2027 if(type0.id() == ID_struct_tag)
2028 to_binary_expr(expr).op0().set(ID_C_lvalue, true);
2029
2031
2032 // Note that in C++ (as opposed to C), the assignment yields
2033 // an lvalue!
2034 expr.set(ID_C_lvalue, true);
2035 return;
2036 }
2037
2038 // It's a non-POD.
2039 // Turn into an operator call
2040
2041 std::string strop="operator";
2042
2043 const irep_idt statement=expr.get(ID_statement);
2044
2045 if(statement==ID_assign)
2046 strop += "=";
2047 else if(statement==ID_assign_shl)
2048 strop += "<<=";
2049 else if(statement==ID_assign_shr)
2050 strop += ">>=";
2051 else if(statement==ID_assign_plus)
2052 strop += "+=";
2053 else if(statement==ID_assign_minus)
2054 strop += "-=";
2055 else if(statement==ID_assign_mult)
2056 strop += "*=";
2057 else if(statement==ID_assign_div)
2058 strop += "/=";
2059 else if(statement==ID_assign_bitand)
2060 strop += "&=";
2061 else if(statement==ID_assign_bitor)
2062 strop += "|=";
2063 else if(statement==ID_assign_bitxor)
2064 strop += "^=";
2065 else
2066 {
2068 error() << "bad assignment operator '" << statement << "'" << eom;
2069 throw 0;
2070 }
2071
2072 const cpp_namet cpp_name(strop, expr.source_location());
2073
2074 // expr.op0() is already typechecked
2075 exprt member(ID_member);
2076 member.set(ID_component_cpp_name, cpp_name);
2078
2080 std::move(member),
2081 {to_binary_expr(expr).op1()},
2083 expr.source_location());
2084
2086
2087 expr=new_expr;
2088}
2089
2091 side_effect_exprt &expr)
2092{
2093 if(expr.operands().size()!=1)
2094 {
2096 error() << "statement " << expr.get_statement()
2097 << " expected to have one operand" << eom;
2098 throw 0;
2099 }
2100
2101 auto &op = to_unary_expr(expr).op();
2102
2104
2105 const typet &tmp_type = op.type();
2106
2107 if(is_number(tmp_type) ||
2108 tmp_type.id()==ID_pointer)
2109 {
2110 // standard stuff
2112 return;
2113 }
2114
2115 // Turn into an operator call
2116
2117 std::string str_op="operator";
2118 bool post=false;
2119
2120 if(expr.get(ID_statement)==ID_preincrement)
2121 str_op += "++";
2122 else if(expr.get(ID_statement)==ID_predecrement)
2123 str_op += "--";
2124 else if(expr.get(ID_statement)==ID_postincrement)
2125 {
2126 str_op += "++";
2127 post=true;
2128 }
2129 else if(expr.get(ID_statement)==ID_postdecrement)
2130 {
2131 str_op += "--";
2132 post=true;
2133 }
2134 else
2135 {
2137 error() << "bad assignment operator '" << expr.get_statement() << "'"
2138 << eom;
2139 throw 0;
2140 }
2141
2142 const cpp_namet cpp_name(str_op, expr.source_location());
2143
2144 exprt member(ID_member);
2145 member.set(ID_component_cpp_name, cpp_name);
2147
2149 std::move(member), {}, uninitialized_typet{}, expr.source_location());
2150
2151 // the odd C++ way to denote the post-inc/dec operator
2152 if(post)
2153 new_expr.arguments().push_back(
2155
2157 expr.swap(new_expr);
2158}
2159
2161{
2162 if(expr.operands().size()!=1)
2163 {
2165 error() << "unary operator * expects one operand" << eom;
2166 throw 0;
2167 }
2168
2169 exprt &op = to_dereference_expr(expr).pointer();
2170 const typet &op_type = op.type();
2171
2172 if(op_type.id() == ID_pointer && op_type.find(ID_to_member).is_not_nil())
2173 {
2175 error() << "pointer-to-member must use "
2176 << "the .* or ->* operators" << eom;
2177 throw 0;
2178 }
2179
2181}
2182
2184{
2185 PRECONDITION(expr.id() == ID_pointer_to_member);
2186 PRECONDITION(expr.operands().size() == 2);
2187
2188 auto &op0 = to_binary_expr(expr).op0();
2189 auto &op1 = to_binary_expr(expr).op1();
2190
2191 if(op1.type().id() != ID_pointer || op1.type().find(ID_to_member).is_nil())
2192 {
2194 error() << "pointer-to-member expected" << eom;
2195 throw 0;
2196 }
2197
2198 typet t0 = op0.type().id() == ID_pointer
2199 ? to_pointer_type(op0.type()).base_type()
2200 : op0.type();
2201
2202 typet t1((const typet &)op1.type().find(ID_to_member));
2203
2204 t0=follow(t0);
2205 t1=follow(t1);
2206
2207 if(t0.id()!=ID_struct)
2208 {
2210 error() << "pointer-to-member type error" << eom;
2211 throw 0;
2212 }
2213
2214 const struct_typet &from_struct=to_struct_type(t0);
2215 const struct_typet &to_struct=to_struct_type(t1);
2216
2217 if(!subtype_typecast(from_struct, to_struct))
2218 {
2220 error() << "pointer-to-member type error" << eom;
2221 throw 0;
2222 }
2223
2225
2226 if(op0.type().id() != ID_pointer)
2227 {
2228 if(op0.id() == ID_dereference)
2229 {
2230 op0 = to_dereference_expr(op0).pointer();
2231 }
2232 else
2233 {
2235 op0.get_bool(ID_C_lvalue),
2236 "pointer-to-member must have lvalue operand");
2237 op0 = address_of_exprt(op0);
2238 }
2239 }
2240
2241 exprt tmp(op1);
2242 tmp.type().set(ID_C_bound, op0);
2243 expr.swap(tmp);
2244 return;
2245}
2246
2248{
2249 if(expr.id()==ID_symbol)
2250 {
2251 // Check if the function body has to be typechecked
2252 symbolt &function_symbol =
2253 symbol_table.get_writeable_ref(expr.get(ID_identifier));
2254
2255 if(function_symbol.value.id() == ID_cpp_not_typechecked)
2256 function_symbol.value.set(ID_is_used, true);
2257 }
2258
2260}
2261
2263{
2264 bool override_constantness = expr.get_bool(ID_C_override_constantness);
2265
2266 // We take care of an ambiguity in the C++ grammar.
2267 // Needs to be done before the operands!
2269
2270 // cpp_name uses get_sub, which can get confused with expressions.
2271 if(expr.id()==ID_cpp_name)
2273 else
2274 {
2275 // This does the operands, and then calls typecheck_expr_main.
2277 }
2278
2279 if(override_constantness)
2280 expr.type().set(ID_C_constant, false);
2281}
2282
2284{
2285 // There is an ambiguity in the C++ grammar as follows:
2286 // (TYPENAME) + expr (typecast of unary plus) vs.
2287 // (expr) + expr (sum of two expressions)
2288 // Same issue with the operators & and - and *
2289
2290 // We figure this out by resolving the type argument
2291 // and re-writing if needed
2292
2293 if(expr.id()!="explicit-typecast")
2294 return;
2295
2296 PRECONDITION(expr.operands().size() == 1);
2297
2298 irep_idt op0_id = to_unary_expr(expr).op().id();
2299
2300 if(
2301 expr.type().id() == ID_cpp_name &&
2302 to_unary_expr(expr).op().operands().size() == 1 &&
2303 (op0_id == ID_unary_plus || op0_id == ID_unary_minus ||
2304 op0_id == ID_address_of || op0_id == ID_dereference))
2305 {
2306 exprt resolve_result=
2307 resolve(
2308 to_cpp_name(expr.type()),
2311
2312 if(resolve_result.id()!=ID_type)
2313 {
2314 // need to re-write the expression
2315 // e.g., (ID) +expr -> ID+expr
2316 exprt new_binary_expr;
2317
2318 new_binary_expr.operands().resize(2);
2319 to_binary_expr(new_binary_expr).op0().swap(expr.type());
2320 to_binary_expr(new_binary_expr)
2321 .op1()
2322 .swap(to_unary_expr(to_unary_expr(expr).op()).op());
2323
2324 if(op0_id==ID_unary_plus)
2325 new_binary_expr.id(ID_plus);
2326 else if(op0_id==ID_unary_minus)
2327 new_binary_expr.id(ID_minus);
2328 else if(op0_id==ID_address_of)
2329 new_binary_expr.id(ID_bitand);
2330 else if(op0_id==ID_dereference)
2331 new_binary_expr.id(ID_mult);
2332
2333 new_binary_expr.add_source_location() =
2335 expr.swap(new_binary_expr);
2336 }
2337 }
2338}
2339
2341{
2342 if(expr.operands().size()!=2)
2343 {
2345 error() << "operator '" << expr.id() << "' expects two operands" << eom;
2346 throw 0;
2347 }
2348
2351
2353}
2354
2359
2361{
2362 if(expr.operands().size()!=2)
2363 {
2365 error() << "comma operator expects two operands" << eom;
2366 throw 0;
2367 }
2368
2369 const auto &op0_type = to_binary_expr(expr).op0().type();
2370
2371 if(op0_type.id() == ID_struct || op0_type.id() == ID_struct_tag)
2372 {
2373 // TODO: check if the comma operator has been overloaded!
2374 }
2375
2377}
2378
configt config
Definition config.cpp:25
constant_exprt from_integer(const mp_integer &int_value, const typet &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
reference_typet reference_type(const typet &subtype)
Definition c_types.cpp:245
empty_typet void_type()
Definition c_types.cpp:250
signedbv_typet signed_int_type()
Definition c_types.cpp:27
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:240
bitvector_typet c_index_type()
Definition c_types.cpp:16
Operator to return the address of an object.
static void make_already_typechecked(exprt &expr)
const exprt & size() const
Definition std_types.h:796
const typet & element_type() const
The type of the elements of the array.
Definition std_types.h:783
exprt & op0()
Definition expr.h:125
exprt & op1()
Definition expr.h:128
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:707
Base class of fixed-width bit-vector types.
Definition std_types.h:865
The Boolean type.
Definition std_types.h:36
virtual void read(const typet &src) override
virtual bool is_subset_of(const qualifierst &other) const override
virtual void typecheck_expr_main(exprt &expr)
symbol_table_baset & symbol_table
virtual void typecheck_expr_address_of(exprt &expr)
virtual void typecheck_expr(exprt &expr)
virtual void do_initializer(exprt &initializer, const typet &type, bool force_constant)
virtual void typecheck_expr_binary_arithmetic(exprt &expr)
virtual void typecheck_expr_sizeof(exprt &expr)
virtual void typecheck_expr_side_effect(side_effect_exprt &expr)
virtual void typecheck_expr_index(exprt &expr)
virtual void typecheck_expr_function_identifier(exprt &expr)
virtual void typecheck_expr_comma(exprt &expr)
virtual exprt do_special_functions(side_effect_expr_function_callt &expr)
virtual void typecheck_side_effect_assignment(side_effect_exprt &expr)
virtual optionalt< symbol_exprt > typecheck_gcc_polymorphic_builtin(const irep_idt &identifier, const exprt::operandst &arguments, const source_locationt &source_location)
virtual void typecheck_expr_operands(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 void typecheck_expr_dereference(exprt &expr)
virtual void typecheck_expr_rel(binary_relation_exprt &expr)
Class type.
Definition std_types.h:325
codet representation of an expression statement.
Definition std_code.h:1394
Base type of functions.
Definition std_types.h:539
std::vector< parametert > parameterst
Definition std_types.h:542
const parameterst & parameters() const
Definition std_types.h:655
const typet & return_type() const
Definition std_types.h:645
struct configt::ansi_ct ansi_c
exprt this_expr
Definition cpp_id.h:76
irep_idt class_identifier
Definition cpp_id.h:75
bool is_qualified() const
Definition cpp_name.h:109
const exprt & as_expr() const
Definition cpp_name.h:137
bool is_destructor() const
Definition cpp_name.h:119
const source_locationt & source_location() const
Definition cpp_name.h:73
cpp_scopet & set_scope(const irep_idt &identifier)
Definition cpp_scopes.h:87
cpp_scopet & current_scope()
Definition cpp_scopes.h:32
exprt::operandst operands
void add_object(const exprt &expr)
bool find_parent(const symbolt &symb, const irep_idt &base_name, irep_idt &identifier)
void typecheck_expr_typecast(exprt &) override
void typecheck_side_effect_assignment(side_effect_exprt &) override
bool implicit_conversion_sequence(const exprt &expr, const typet &type, exprt &new_expr, unsigned &rank)
implicit conversion sequence
optionalt< codet > cpp_destructor(const source_locationt &source_location, const exprt &object)
void typecheck_type(typet &) override
void explicit_typecast_ambiguity(exprt &)
template_mapt template_map
bool reinterpret_typecast(const exprt &expr, const typet &type, exprt &new_expr, bool check_constantness=true)
void convert_pmop(exprt &expr)
void typecheck_expr_sizeof(exprt &) override
void typecheck_code(codet &) override
void typecheck_expr_explicit_typecast(exprt &)
void implicit_typecast(exprt &expr, const typet &type) override
void typecheck_cast_expr(exprt &)
void typecheck_expr_dereference(exprt &) override
void typecheck_side_effect_function_call(side_effect_expr_function_callt &) override
bool cpp_is_pod(const typet &type) const
bool get_component(const source_locationt &source_location, const exprt &object, const irep_idt &component_name, exprt &member)
bool const_typecast(const exprt &expr, const typet &type, exprt &new_expr)
void new_temporary(const source_locationt &source_location, const typet &, const exprt::operandst &ops, exprt &temporary)
void typecheck_expr_trinary(if_exprt &) override
void typecheck_expr_rel(binary_relation_exprt &) override
bool standard_conversion_function_to_pointer(const exprt &expr, exprt &new_expr) const
Function-to-pointer conversion.
bool standard_conversion_array_to_pointer(const exprt &expr, exprt &new_expr) const
Array-to-pointer conversion.
bool dynamic_typecast(const exprt &expr, const typet &type, exprt &new_expr)
void add_method_body(symbolt *_method_symbol)
void typecheck_expr_binary_arithmetic(exprt &) override
void typecheck_expr_delete(exprt &)
optionalt< codet > cpp_constructor(const source_locationt &source_location, const exprt &object, const exprt::operandst &operands)
void typecheck_expr_main(exprt &) override
Called after the operands are done.
void elaborate_class_template(const typet &type)
elaborate class template instances
bool operator_is_overloaded(exprt &)
bool standard_conversion_lvalue_to_rvalue(const exprt &expr, exprt &new_expr) const
Lvalue-to-rvalue conversion.
void typecheck_expr_new(exprt &)
void add_implicit_dereference(exprt &)
void typecheck_expr_cpp_name(exprt &, const cpp_typecheck_fargst &)
void typecheck_expr(exprt &) override
void typecheck_expr_side_effect(side_effect_exprt &) override
void typecheck_expr_comma(exprt &) override
bool static_typecast(const exprt &expr, const typet &type, exprt &new_expr, bool check_constantness=true)
bool subtype_typecast(const struct_typet &from, const struct_typet &to) const
void typecheck_expr_explicit_constructor_call(exprt &)
void typecheck_function_expr(exprt &, const cpp_typecheck_fargst &)
void typecheck_method_application(side_effect_expr_function_callt &)
std::string to_string(const typet &) override
void typecheck_expr_this(exprt &)
void typecheck_expr_throw(exprt &)
bool overloadable(const exprt &)
void typecheck_expr_index(exprt &) override
void typecheck_side_effect_inc_dec(side_effect_exprt &)
void zero_initializer(const exprt &object, const typet &type, const source_locationt &source_location, exprt::operandst &ops)
void typecheck_function_call_arguments(side_effect_expr_function_callt &) override
void typecheck_expr_ptrmember(exprt &) override
exprt resolve(const cpp_namet &cpp_name, const cpp_typecheck_resolvet::wantt want, const cpp_typecheck_fargst &fargs, bool fail_with_exception=true)
cpp_scopest cpp_scopes
void typecheck_expr_address_of(exprt &) override
void typecheck_expr_function_identifier(exprt &) override
void typecheck_expr_member(exprt &) override
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:39
bool empty() const
Definition dstring.h:90
Base class for all expressions.
Definition expr.h:56
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition expr.cpp:147
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
Definition expr.h:155
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:204
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
const source_locationt & source_location() const
Definition expr.h:223
source_locationt & add_source_location()
Definition expr.h:228
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition expr.h:162
The Boolean constant false.
Definition std_expr.h:3017
The trinary if-then-else operator.
Definition std_expr.h:2323
Array index operator.
Definition std_expr.h:1410
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition irep.h:372
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:490
const irept & find(const irep_idt &name) const
Definition irep.cpp:101
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
void remove(const irep_idt &name)
Definition irep.cpp:95
void set(const irep_idt &name, const irep_idt &value)
Definition irep.h:420
bool is_not_nil() const
Definition irep.h:380
subt & get_sub()
Definition irep.h:456
void make_nil()
Definition irep.h:454
void swap(irept &irep)
Definition irep.h:442
const irep_idt & id() const
Definition irep.h:396
irept & add(const irep_idt &name)
Definition irep.cpp:111
bool is_nil() const
Definition irep.h:376
const std::string & get_string(const irep_idt &name) const
Definition irep.h:409
const exprt & compound() const
Definition std_expr.h:2843
source_locationt source_location
Definition message.h:247
mstreamt & error() const
Definition message.h:399
static eomt eom
Definition message.h:297
exprt & op0()
Definition std_expr.h:877
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition namespace.cpp:49
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The NIL expression.
Definition std_expr.h:3026
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
const typet & base_type() const
The type of the data what we point to.
A side_effect_exprt representation of a function call side effect.
Definition std_code.h:1692
exprt::operandst & arguments()
Definition std_code.h:1718
An expression containing a side effect.
Definition std_code.h:1450
const irep_idt & get_statement() const
Definition std_code.h:1472
A struct tag type, i.e., struct_typet with an identifier.
Definition std_types.h:449
Structure type, corresponds to C style structs.
Definition std_types.h:231
const basest & bases() const
Get the collection of base classes/structs.
Definition std_types.h:262
bool has_base(const irep_idt &id) const
Test whether id is a base class/struct.
Definition std_types.h:285
Base type for structs and unions.
Definition std_types.h:62
const componentst & components() const
Definition std_types.h:147
const componentt & get_component(const irep_idt &component_name) const
Get the reference to a component with given name.
Definition std_types.cpp:63
bool is_incomplete() const
A struct/union may be incomplete.
Definition std_types.h:185
std::vector< componentt > componentst
Definition std_types.h:140
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
Symbol table entry.
Definition symbol.h:28
typet type
Type of symbol.
Definition symbol.h:31
exprt value
Initial value of symbol.
Definition symbol.h:34
void build(const template_typet &template_type, const cpp_template_args_tct &template_args)
void print(std::ostream &out) const
exprt & op0()
Definition expr.h:125
exprt & op1()
Definition expr.h:128
exprt & op2()
Definition expr.h:131
The Boolean constant true.
Definition std_expr.h:3008
Semantic type conversion.
Definition std_expr.h:2017
The type of an expression, extends irept.
Definition type.h:29
source_locationt & add_source_location()
Definition type.h:77
const exprt & op() const
Definition std_expr.h:326
irept cpp_exception_list(const typet &src, const namespacet &ns)
turns a type into a list of relevant exception IDs
C++ Language Type Checking.
cpp_namet & to_cpp_name(irept &cpp_name)
Definition cpp_name.h:148
std::string cpp_type2name(const typet &type)
C++ Language Module.
C++ Language Type Checking.
static exprt collect_comma_expression(const exprt &src)
struct operator_entryt operators[]
C++ Language Type Checking.
symbol_exprt cpp_symbol_expr(const symbolt &symbol)
Definition cpp_util.cpp:14
std::string type2cpp(const typet &type, const namespacet &ns)
Definition expr2cpp.cpp:503
Expression Initialization.
bool is_number(const typet &type)
Returns true if the type is a rational, real, integer, natural, complex, unsignedbv,...
Mathematical types.
API to expression classes for Pointers.
bool is_reference(const typet &type)
Returns true if the type is a reference.
const reference_typet & to_reference_type(const typet &type)
Cast a typet to a reference_typet.
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.
optionalt< exprt > size_of_expr(const typet &type, const namespacet &ns)
Pointer Logic.
BigInt mp_integer
Definition smt_terms.h:18
#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_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
Definition std_code.h:1739
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition std_expr.cpp:77
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:660
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:361
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:932
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:2886
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:222
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:744
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:844
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition std_types.h:214
const class_typet & to_class_type(const typet &type)
Cast a typet to a class_typet.
Definition std_types.h:381
std::size_t int_width
Definition config.h:134
Author: Diffblue Ltd.
dstringt irep_idt