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