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