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