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