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 #include <cstdlib>
15 
16 #include <util/std_types.h>
17 #include <util/arith_tools.h>
18 #include <util/std_expr.h>
19 #include <util/config.h>
20 #include <util/simplify_expr.h>
21 #include <util/base_type.h>
22 
23 #include <util/c_types.h>
24 #include <ansi-c/c_qualifiers.h>
25 #include <ansi-c/c_sizeof.h>
26 
28 
29 #include "cpp_type2name.h"
30 #include "cpp_convert_type.h"
31 #include "cpp_exception_id.h"
32 #include "expr2cpp.h"
33 
35  const symbolt &symb,
36  const irep_idt &base_name,
37  irep_idt &identifier)
38 {
39  forall_irep(bit, symb.type.find(ID_bases).get_sub())
40  {
41  if(lookup(bit->find(ID_type).get(ID_identifier)).base_name == base_name)
42  {
43  identifier=bit->find(ID_type).get(ID_identifier);
44  return true;
45  }
46  }
47 
48  return false;
49 }
50 
53 {
54  if(expr.id()==ID_cpp_name)
56  else if(expr.id()=="cpp-this")
57  typecheck_expr_this(expr);
58  else if(expr.id()=="pointer-to-member")
59  convert_pmop(expr);
60  else if(expr.id()=="new_object")
61  {
62  }
63  else if(operator_is_overloaded(expr))
64  {
65  }
66  else if(expr.id()=="explicit-typecast")
68  else if(expr.id()=="explicit-constructor-call")
70  else if(expr.is_nil())
71  {
72  #if 0
73  std::cerr << "cpp_typecheckt::typecheck_expr_main got nil\n";
74  #endif
75  abort();
76  }
77  else if(expr.id()==ID_code)
78  {
79  #if 0
80  std::cerr << "cpp_typecheckt::typecheck_expr_main got code\n";
81  #endif
82  abort();
83  }
84  else if(expr.id()==ID_symbol)
85  {
86  #if 0
87  std::cout << "E: " << expr.pretty() << '\n';
88  std::cerr << "cpp_typecheckt::typecheck_expr_main got symbol\n";
89  abort();
90  #endif
91  }
92  else if(expr.id()=="__is_base_of")
93  {
94  // an MS extension
95  // http://msdn.microsoft.com/en-us/library/ms177194(v=vs.80).aspx
96 
97  typet base=static_cast<const typet &>(expr.find("type_arg1"));
98  typet deriv=static_cast<const typet &>(expr.find("type_arg2"));
99 
100  typecheck_type(base);
101  typecheck_type(deriv);
102 
103  follow_symbol(base);
104  follow_symbol(deriv);
105 
106  if(base.id()!=ID_struct || deriv.id()!=ID_struct)
107  expr=false_exprt();
108  else
109  {
110  irep_idt base_name=base.get(ID_name);
111  const class_typet &class_type=to_class_type(deriv);
112 
113  if(class_type.has_base(base_name))
114  expr=true_exprt();
115  else
116  expr=false_exprt();
117  }
118  }
119  else if(expr.id()==ID_msc_uuidof)
120  {
121  // these appear to have type "struct _GUID"
122  // and they are lvalues!
123  expr.type()=symbol_typet("tag-_GUID");
124  follow(expr.type());
125  expr.set(ID_C_lvalue, true);
126  }
127  else if(expr.id()==ID_noexcept)
128  {
129  // TODO
130  expr=false_exprt();
131  }
132  else if(expr.id()==ID_initializer_list)
133  {
134  expr.type().id(ID_initializer_list);
135  }
136  else
138 }
139 
141 {
142  assert(expr.operands().size()==3);
143 
144  implicit_typecast(expr.op0(), bool_typet());
145 
146  if(expr.op1().type().id()==ID_empty ||
147  expr.op1().type().id()==ID_empty)
148  {
149  if(expr.op1().get_bool(ID_C_lvalue))
150  {
151  exprt e1(expr.op1());
153  {
154  error().source_location=e1.find_source_location();
155  error() << "error: lvalue to rvalue conversion" << eom;
156  throw 0;
157  }
158  }
159 
160  if(expr.op1().type().id()==ID_array)
161  {
162  exprt e1(expr.op1());
164  {
165  error().source_location=e1.find_source_location();
166  error() << "error: array to pointer conversion" << eom;
167  throw 0;
168  }
169  }
170 
171  if(expr.op1().type().id()==ID_code)
172  {
173  exprt e1(expr.op1());
175  {
176  error().source_location=e1.find_source_location();
177  error() << "error: function to pointer conversion" << eom;
178  throw 0;
179  }
180  }
181 
182  if(expr.op2().get_bool(ID_C_lvalue))
183  {
184  exprt e2(expr.op2());
186  {
187  error().source_location=e2.find_source_location();
188  error() << "error: lvalue to rvalue conversion" << eom;
189  throw 0;
190  }
191  }
192 
193  if(expr.op2().type().id()==ID_array)
194  {
195  exprt e2(expr.op2());
197  {
198  error().source_location=e2.find_source_location();
199  error() << "error: array to pointer conversion" << eom;
200  throw 0;
201  }
202  }
203 
204  if(expr.op2().type().id()==ID_code)
205  {
206  exprt e2(expr.op2());
208  {
210  error() << "error: function to pointer conversion" << eom;
211  throw 0;
212  }
213  }
214 
215  if(expr.op1().get(ID_statement)==ID_throw &&
216  expr.op2().get(ID_statement)!=ID_throw)
217  expr.type()=expr.op2().type();
218  else if(expr.op2().get(ID_statement)==ID_throw &&
219  expr.op1().get(ID_statement)!=ID_throw)
220  expr.type()=expr.op1().type();
221  else if(expr.op1().type().id()==ID_empty &&
222  expr.op2().type().id()==ID_empty)
223  expr.type()=empty_typet();
224  else
225  {
227  error() << "error: bad types for operands" << eom;
228  throw 0;
229  }
230  return;
231  }
232 
233  if(expr.op1().type() == expr.op2().type())
234  {
235  c_qualifierst qual1, qual2;
236  qual1.read(expr.op1().type());
237  qual2.read(expr.op2().type());
238 
239  if(qual1.is_subset_of(qual2))
240  expr.type()=expr.op1().type();
241  else
242  expr.type()=expr.op2().type();
243  }
244  else
245  {
246  exprt e1=expr.op1();
247  exprt e2=expr.op2();
248 
249  if(implicit_conversion_sequence(expr.op1(), expr.op2().type(), e1))
250  {
251  expr.type()=e1.type();
252  expr.op1().swap(e1);
253  }
254  else if(implicit_conversion_sequence(expr.op2(), expr.op1().type(), e2))
255  {
256  expr.type()=e2.type();
257  expr.op2().swap(e2);
258  }
259  else if(expr.op1().type().id()==ID_array &&
260  expr.op2().type().id()==ID_array &&
261  expr.op1().type().subtype() == expr.op2().type().subtype())
262  {
263  // array-to-pointer conversion
264 
265  index_exprt index1;
266  index1.array()=expr.op1();
267  index1.index()=from_integer(0, index_type());
268  index1.type()=expr.op1().type().subtype();
269 
270  index_exprt index2;
271  index2.array()=expr.op2();
272  index2.index()=from_integer(0, index_type());
273  index2.type()=expr.op2().type().subtype();
274 
275  address_of_exprt addr1(index1);
276  address_of_exprt addr2(index2);
277 
278  expr.op1()=addr1;
279  expr.op2()=addr2;
280  expr.type()=addr1.type();
281  return;
282  }
283  else
284  {
286  error() << "error: types are incompatible.\n"
287  << "I got `" << type2cpp(expr.op1().type(), *this)
288  << "' and `" << type2cpp(expr.op2().type(), *this)
289  << "'." << eom;
290  throw 0;
291  }
292  }
293 
294  if(expr.op1().get_bool(ID_C_lvalue) &&
295  expr.op2().get_bool(ID_C_lvalue))
296  expr.set(ID_C_lvalue, true);
297 
298  return;
299 }
300 
302 {
304  expr,
306 }
307 
309 {
310  // We need to overload, "sizeof-expression" can be mis-parsed
311  // as a type.
312 
313  if(expr.operands().empty())
314  {
315  const typet &type=
316  static_cast<const typet &>(expr.find(ID_type_arg));
317 
318  if(type.id()==ID_cpp_name)
319  {
320  // sizeof(X) may be ambiguous -- X can be either a type or
321  // an expression.
322 
323  cpp_typecheck_fargst fargs;
324 
325  exprt symbol_expr=resolve(
326  to_cpp_name(static_cast<const irept &>(type)),
328  fargs);
329 
330  if(symbol_expr.id()!=ID_type)
331  {
332  expr.copy_to_operands(symbol_expr);
333  expr.remove(ID_type_arg);
334  }
335  }
336  else if(type.id()==ID_array)
337  {
338  // sizeof(expr[index]) can be parsed as an array type!
339 
340  if(type.subtype().id()==ID_cpp_name)
341  {
342  cpp_typecheck_fargst fargs;
343 
344  exprt symbol_expr=resolve(
345  to_cpp_name(static_cast<const irept &>(type.subtype())),
347  fargs);
348 
349  if(symbol_expr.id()!=ID_type)
350  {
351  // _NOT_ a type
352  index_exprt index_expr(symbol_expr, to_array_type(type).size());
353  expr.copy_to_operands(index_expr);
354  expr.remove(ID_type_arg);
355  }
356  }
357  }
358  }
359 
361 }
362 
364 {
366 }
367 
369  exprt &expr,
370  const cpp_typecheck_fargst &fargs)
371 {
372  if(expr.id()==ID_cpp_name)
373  typecheck_expr_cpp_name(expr, fargs);
374  else if(expr.id()==ID_member)
375  {
377  typecheck_expr_member(expr, fargs);
378  }
379  else if(expr.id()==ID_ptrmember)
380  {
383 
384  // is operator-> overloaded?
385  if(expr.op0().type().id() != ID_pointer)
386  {
387  std::string op_name="operator->";
388 
389  // turn this into a function call
390  side_effect_expr_function_callt function_call;
391  function_call.arguments().reserve(expr.operands().size());
392  function_call.add_source_location()=expr.source_location();
393 
394  // first do function/operator
395  cpp_namet cpp_name;
396  cpp_name.get_sub().push_back(irept(ID_name));
397  cpp_name.get_sub().back().set(ID_identifier, op_name);
398  cpp_name.get_sub().back().add(ID_C_source_location)=
399  expr.source_location();
400 
401  function_call.function()=
402  static_cast<const exprt &>(
403  static_cast<const irept &>(cpp_name));
404 
405  // now do the argument
406  function_call.arguments().push_back(expr.op0());
408 
409  exprt tmp("already_typechecked");
410  tmp.copy_to_operands(function_call);
411  function_call.swap(tmp);
412 
413  expr.op0().swap(function_call);
414  typecheck_function_expr(expr, fargs);
415  return;
416  }
417 
418  typecheck_expr_ptrmember(expr, fargs);
419  }
420  else
421  typecheck_expr(expr);
422 }
423 
425 {
426  // at least one argument must have class or enumerated type
427 
428  forall_operands(it, expr)
429  {
430  typet t=follow(it->type());
431 
432  if(is_reference(t))
433  t=t.subtype();
434 
435  if(t.id()==ID_struct ||
436  t.id()==ID_union ||
437  t.id()==ID_c_enum)
438  return true;
439  }
440 
441  return false;
442 }
443 
445 {
446  const irep_idt id;
447  const char *op_name;
448 } const operators[] =
449 {
450  { ID_plus, "+" },
451  { ID_minus, "-" },
452  { ID_mult, "*" },
453  { ID_div, "/" },
454  { ID_bitnot, "~" },
455  { ID_bitand, "&" },
456  { ID_bitor, "|" },
457  { ID_bitxor, "^" },
458  { ID_not, "!" },
459  { ID_unary_minus, "-" },
460  { ID_and, "&&" },
461  { ID_or, "||" },
462  { ID_not, "!" },
463  { ID_index, "[]" },
464  { ID_equal, "==" },
465  { ID_lt, "<"},
466  { ID_le, "<="},
467  { ID_gt, ">"},
468  { ID_ge, ">="},
469  { ID_shl, "<<"},
470  { ID_shr, ">>"},
471  { ID_notequal, "!=" },
472  { ID_dereference, "*" },
473  { ID_ptrmember, "->" },
474  { irep_idt(), nullptr }
475 };
476 
478 {
479  // Check argument types first.
480  // At least one struct/enum operand is required.
481 
482  if(!overloadable(expr))
483  return false;
484  else if(expr.id()==ID_dereference &&
485  expr.get_bool(ID_C_implicit))
486  return false;
487 
488  assert(expr.operands().size()>=1);
489 
490  if(expr.id()=="explicit-typecast")
491  {
492  // the cast operator can be overloaded
493 
494  typet t=expr.type();
495  typecheck_type(t);
496  std::string op_name=std::string("operator")+"("+cpp_type2name(t)+")";
497 
498  // turn this into a function call
499  side_effect_expr_function_callt function_call;
500  function_call.arguments().reserve(expr.operands().size());
501  function_call.add_source_location()=expr.source_location();
502 
503  cpp_namet cpp_name;
504  cpp_name.get_sub().push_back(irept(ID_name));
505  cpp_name.get_sub().back().set(ID_identifier, op_name);
506  cpp_name.get_sub().back().add(ID_C_source_location)=expr.source_location();
507 
508  // See if the struct declares the cast operator as a member
509  bool found_in_struct=false;
510  assert(!expr.operands().empty());
511  typet t0(follow(expr.op0().type()));
512 
513  if(t0.id()==ID_struct)
514  {
515  const struct_typet &struct_type=
516  to_struct_type(t0);
517 
518  const struct_typet::componentst &components=
519  struct_type.components();
520 
521  for(struct_typet::componentst::const_iterator
522  it=components.begin();
523  it!=components.end();
524  it++)
525  {
526  if(!it->get_bool(ID_from_base) &&
527  it->get(ID_base_name) == op_name)
528  {
529  found_in_struct=true;
530  break;
531  }
532  }
533  }
534 
535  if(!found_in_struct)
536  return false;
537 
538  {
539  exprt member(ID_member);
540  member.add(ID_component_cpp_name)= cpp_name;
541 
542  exprt tmp("already_typechecked");
543  tmp.copy_to_operands(expr.op0());
544  member.copy_to_operands(tmp);
545 
546  function_call.function()=member;
547  }
548 
549  if(expr.operands().size()>1)
550  {
551  for(exprt::operandst::const_iterator
552  it=(expr.operands().begin()+1);
553  it!=(expr).operands().end();
554  it++)
555  function_call.arguments().push_back(*it);
556  }
557 
559 
560  if(expr.id()==ID_ptrmember)
561  {
562  add_implicit_dereference(function_call);
563  exprt tmp("already_typechecked");
564  tmp.move_to_operands(function_call);
565  expr.op0().swap(tmp);
566  typecheck_expr(expr);
567  return true;
568  }
569 
570  expr.swap(function_call);
571  return true;
572  }
573 
574  for(const operator_entryt *e=operators;
575  !e->id.empty();
576  e++)
577  if(expr.id()==e->id)
578  {
579  if(expr.id()==ID_dereference)
580  assert(!expr.get_bool(ID_C_implicit));
581 
582  std::string op_name=std::string("operator")+e->op_name;
583 
584  // first do function/operator
585  cpp_namet cpp_name;
586  cpp_name.get_sub().push_back(irept(ID_name));
587  cpp_name.get_sub().back().set(ID_identifier, op_name);
588  cpp_name.get_sub().back().add(ID_C_source_location)=
589  expr.source_location();
590 
591  // turn this into a function call
592  side_effect_expr_function_callt function_call;
593  function_call.arguments().reserve(expr.operands().size());
594  function_call.add_source_location()=expr.source_location();
595 
596  // There are two options to overload an operator:
597  //
598  // 1. In the scope of a as a.operator(b, ...)
599  // 2. Anywhere in scope as operator(a, b, ...)
600  //
601  // Using both is not allowed.
602  //
603  // We try and fail silently, maybe conversions will work
604  // instead.
605 
606  // go into scope of first operand
607  if(expr.op0().type().id()==ID_symbol &&
608  follow(expr.op0().type()).id()==ID_struct)
609  {
610  const irep_idt &struct_identifier=
611  expr.op0().type().get(ID_identifier);
612 
613  // get that scope
614  cpp_save_scopet save_scope(cpp_scopes);
615  cpp_scopes.set_scope(struct_identifier);
616 
617  // build fargs for resolver
618  cpp_typecheck_fargst fargs;
619  fargs.operands=expr.operands();
620  fargs.has_object=true;
621  fargs.in_use=true;
622 
623  // should really be a qualified search
624  exprt resolve_result=resolve(
625  cpp_name, cpp_typecheck_resolvet::wantt::VAR, fargs, false);
626 
627  if(resolve_result.is_not_nil())
628  {
629  // Found! We turn op(a, b, ...) into a.op(b, ...)
630  {
631  exprt member(ID_member);
632  member.add(ID_component_cpp_name)=cpp_name;
633 
634  exprt tmp("already_typechecked");
635  tmp.copy_to_operands(expr.op0());
636  member.copy_to_operands(tmp);
637 
638  function_call.function()=member;
639  }
640 
641  if(expr.operands().size()>1)
642  {
643  // skip first
644  for(exprt::operandst::const_iterator
645  it=expr.operands().begin()+1;
646  it!=expr.operands().end();
647  it++)
648  function_call.arguments().push_back(*it);
649  }
650 
652 
653  expr=function_call;
654 
655  return true;
656  }
657  }
658 
659  // 2nd option!
660  {
661  cpp_typecheck_fargst fargs;
662  fargs.operands=expr.operands();
663  fargs.has_object=false;
664  fargs.in_use=true;
665 
666  exprt resolve_result=resolve(
667  cpp_name, cpp_typecheck_resolvet::wantt::VAR, fargs, false);
668 
669  if(resolve_result.is_not_nil())
670  {
671  // found!
672  function_call.function()=
673  static_cast<const exprt &>(
674  static_cast<const irept &>(cpp_name));
675 
676  // now do arguments
677  forall_operands(it, expr)
678  function_call.arguments().push_back(*it);
679 
681 
682  if(expr.id()==ID_ptrmember)
683  {
684  add_implicit_dereference(function_call);
685  exprt tmp("already_typechecked");
686  tmp.move_to_operands(function_call);
687  expr.op0()=tmp;
688  typecheck_expr(expr);
689  return true;
690  }
691 
692  expr=function_call;
693 
694  return true;
695  }
696  }
697  }
698 
699  return false;
700 }
701 
703 {
704  if(expr.operands().size()!=1)
705  {
707  error() << "address_of expects one operand" << eom;
708  throw 0;
709  }
710 
711  exprt &op=expr.op0();
712 
713  if(!op.get_bool(ID_C_lvalue) && expr.type().id()==ID_code)
714  {
716  error() << "expr not an lvalue" << eom;
717  throw 0;
718  }
719 
720  if(expr.op0().type().id()==ID_code)
721  {
722  // we take the address of the method.
723  assert(expr.op0().id()==ID_member);
724  exprt symb=cpp_symbol_expr(lookup(expr.op0().get(ID_component_name)));
725  address_of_exprt address(symb, pointer_type(symb.type()));
726  address.set(ID_C_implicit, true);
727  expr.op0().swap(address);
728  }
729 
730  if(expr.op0().id()==ID_address_of &&
731  expr.op0().get_bool(ID_C_implicit))
732  {
733  // must be the address of a function
734  code_typet &code_type=to_code_type(op.type().subtype());
735 
736  code_typet::parameterst &args=code_type.parameters();
737  if(args.size() > 0 && args[0].get(ID_C_base_name)==ID_this)
738  {
739  // it's a pointer to member function
740  typet symbol(ID_symbol);
741  symbol.set(ID_identifier, code_type.get(ID_C_member_name));
742  expr.op0().type().add("to-member")=symbol;
743 
744  if(code_type.get_bool(ID_C_is_virtual))
745  {
747  error() << "error: pointers to virtual methods"
748  << " are currently not implemented" << eom;
749  throw 0;
750  }
751  }
752  }
753 
754  // the C front end does not know about references
755  const bool is_ref=is_reference(expr.type());
757  if(is_ref)
758  expr.type()=reference_type(expr.type().subtype());
759 }
760 
762 {
763  // these are of type void
764  expr.type()=empty_typet();
765 
766  assert(expr.operands().size()==1 ||
767  expr.operands().empty());
768 
769  if(expr.operands().size()==1)
770  {
771  // nothing really to do; one can throw _almost_ anything
772  const typet &exception_type=expr.op0().type();
773 
774  if(follow(exception_type).id()==ID_empty)
775  {
777  error() << "cannot throw void" << eom;
778  throw 0;
779  }
780 
781  // annotate the relevant exception IDs
782  expr.set(ID_exception_list,
783  cpp_exception_list(exception_type, *this));
784  }
785 }
786 
788 {
789  // next, find out if we do an array
790 
791  if(expr.type().id()==ID_array)
792  {
793  // first typecheck subtype
794  typecheck_type(expr.type().subtype());
795 
796  // typecheck the size
797  exprt &size=to_array_type(expr.type()).size();
798  typecheck_expr(size);
799 
800  bool size_is_unsigned=(size.type().id()==ID_unsignedbv);
801  typet integer_type(size_is_unsigned?ID_unsignedbv:ID_signedbv);
802  integer_type.set(ID_width, config.ansi_c.int_width);
803  implicit_typecast(size, integer_type);
804 
805  expr.set(ID_statement, ID_cpp_new_array);
806 
807  // save the size expression
808  expr.set(ID_size, to_array_type(expr.type()).size());
809 
810  // new actually returns a pointer, not an array
811  pointer_typet ptr_type=
812  pointer_type(expr.type().subtype());
813  expr.type().swap(ptr_type);
814  }
815  else
816  {
817  // first typecheck type
818  typecheck_type(expr.type());
819 
820  expr.set(ID_statement, ID_cpp_new);
821 
822  pointer_typet ptr_type=pointer_type(expr.type());
823  expr.type().swap(ptr_type);
824  }
825 
826  exprt object_expr("new_object", expr.type().subtype());
827  object_expr.set(ID_C_lvalue, true);
828 
829  {
830  exprt tmp("already_typechecked");
831  tmp.move_to_operands(object_expr);
832  object_expr.swap(tmp);
833  }
834 
835  // not yet typechecked-stuff
836  exprt &initializer=static_cast<exprt &>(expr.add(ID_initializer));
837 
838  // arrays must not have an initializer
839  if(!initializer.operands().empty() &&
840  expr.get(ID_statement)==ID_cpp_new_array)
841  {
843  error() << "new with array type must not use initializer" << eom;
844  throw 0;
845  }
846 
847  exprt code=
849  expr.find_source_location(),
850  object_expr,
851  initializer.operands());
852 
853  expr.add(ID_initializer).swap(code);
854 
855  // we add the size of the object for convenience of the
856  // runtime library
857 
858  exprt &sizeof_expr=static_cast<exprt &>(expr.add(ID_sizeof));
859  sizeof_expr=c_sizeof(expr.type().subtype(), *this);
860  sizeof_expr.add("#c_sizeof_type")=expr.type().subtype();
861 }
862 
864 {
865  exprt result;
866 
867  if(src.id()==ID_comma)
868  {
869  assert(src.operands().size()==2);
870  result=collect_comma_expression(src.op0());
871  result.copy_to_operands(src.op1());
872  }
873  else
874  result.copy_to_operands(src);
875 
876  return result;
877 }
878 
880 {
881  // these can have 0 or 1 arguments
882 
883  if(expr.operands().empty())
884  {
885  // Default value, e.g., int()
886  typecheck_type(expr.type());
887  exprt new_expr=
889  expr.type(),
890  expr.find_source_location(),
891  *this,
893 
894  new_expr.add_source_location()=expr.source_location();
895  expr=new_expr;
896  }
897  else if(expr.operands().size()==1)
898  {
899  // Explicitly given value, e.g., int(1).
900  // There is an expr-vs-type ambiguity, as it is possible to write
901  // (f)(1), where 'f' is a function symbol and not a type.
902  // This also exists with a "comma expression", e.g.,
903  // (f)(1, 2, 3)
904 
905  if(expr.type().id()==ID_cpp_name)
906  {
907  // try to resolve as type
908  cpp_typecheck_fargst fargs;
909 
910  exprt symbol_expr=resolve(
911  to_cpp_name(static_cast<const irept &>(expr.type())),
913  fargs,
914  false); // fail silently
915 
916  if(symbol_expr.id()==ID_type)
917  expr.type()=symbol_expr.type();
918  else
919  {
920  // It's really a function call. Note that multiple arguments
921  // become a comma expression, and that these are already typechecked.
923 
924  f_call.add_source_location()=expr.source_location();
925  f_call.function().swap(expr.type());
926  f_call.arguments()=collect_comma_expression(expr.op0()).operands();
927 
929 
930  expr.swap(f_call);
931  return;
932  }
933  }
934  else
935  typecheck_type(expr.type());
936 
937  exprt new_expr;
938 
939  if(const_typecast(expr.op0(), expr.type(), new_expr) ||
940  static_typecast(expr.op0(), expr.type(), new_expr, false) ||
941  reinterpret_typecast(expr.op0(), expr.type(), new_expr, false))
942  {
943  expr=new_expr;
945  }
946  else
947  {
949  error() << "invalid explicit cast:\n"
950  << "operand type: `" << to_string(expr.op0().type())
951  << "'\n"
952  << "casting to: `" << to_string(expr.type()) << "'"
953  << eom;
954  throw 0;
955  }
956  }
957  else
958  {
960  error() << "explicit typecast expects 0 or 1 operands" << eom;
961  throw 0;
962  }
963 }
964 
966 {
967  typecheck_type(expr.type());
968 
969  if(cpp_is_pod(expr.type()))
970  {
971  expr.id("explicit-typecast");
972  typecheck_expr_main(expr);
973  }
974  else
975  {
976  assert(expr.type().id()==ID_struct);
977 
978  typet symb(ID_symbol);
979  symb.set(ID_identifier, expr.type().get(ID_name));
980  symb.add_source_location()=expr.source_location();
981 
982  exprt e=expr;
983  new_temporary(e.source_location(), symb, e.operands(), expr);
984  }
985 }
986 
988 {
990  {
992  error() << "`this' is not allowed here" << eom;
993  throw 0;
994  }
995 
996  const exprt &this_expr=cpp_scopes.current_scope().this_expr;
997  const source_locationt source_location=expr.find_source_location();
998 
999  assert(this_expr.is_not_nil());
1000  assert(this_expr.type().id()==ID_pointer);
1001 
1002  expr=this_expr;
1003  expr.add_source_location()=source_location;
1004 }
1005 
1007 {
1008  if(expr.operands().size()!=1)
1009  {
1011  error() << "delete expects one operand" << eom;
1012  throw 0;
1013  }
1014 
1015  const irep_idt statement=expr.get(ID_statement);
1016 
1017  if(statement==ID_cpp_delete)
1018  {
1019  }
1020  else if(statement==ID_cpp_delete_array)
1021  {
1022  }
1023  else
1024  assert(false);
1025 
1026  typet pointer_type=follow(expr.op0().type());
1027 
1028  if(pointer_type.id()!=ID_pointer)
1029  {
1031  error() << "delete takes a pointer type operand, but got `"
1032  << to_string(pointer_type) << "'" << eom;
1033  throw 0;
1034  }
1035 
1036  // remove any const-ness of the argument
1037  // (which would impair the call to the destructor)
1038  pointer_type.subtype().remove(ID_C_constant);
1039 
1040  // delete expressions are always void
1041  expr.type()=typet(ID_empty);
1042 
1043  // we provide the right destructor, for the convenience
1044  // of later stages
1045  exprt new_object(ID_new_object, pointer_type.subtype());
1046  new_object.add_source_location()=expr.source_location();
1047  new_object.set(ID_C_lvalue, true);
1048 
1049  already_typechecked(new_object);
1050 
1051  codet destructor_code=cpp_destructor(
1052  expr.source_location(),
1054  new_object);
1055 
1056  // this isn't typechecked yet
1057  if(destructor_code.is_not_nil())
1058  typecheck_code(destructor_code);
1059 
1060  expr.set(ID_destructor, destructor_code);
1061 }
1062 
1064 {
1065  // should not be called
1066  #if 0
1067  std::cout << "E: " << expr.pretty() << '\n';
1068  assert(0);
1069  #endif
1070 }
1071 
1073  exprt &expr,
1074  const cpp_typecheck_fargst &fargs)
1075 {
1076  if(expr.operands().size()!=1)
1077  {
1079  error() << "error: member operator expects one operand" << eom;
1080  throw 0;
1081  }
1082 
1083  exprt &op0=expr.op0();
1085 
1086  // The notation for explicit calls to destructors can be used regardless
1087  // of whether the type defines a destructor. This allows you to make such
1088  // explicit calls without knowing if a destructor is defined for the type.
1089  // An explicit call to a destructor where none is defined has no effect.
1090 
1091  if(expr.find(ID_component_cpp_name).is_not_nil() &&
1092  to_cpp_name(expr.find(ID_component_cpp_name)).is_destructor() &&
1093  follow(op0.type()).id()!=ID_struct)
1094  {
1095  exprt tmp("cpp_dummy_destructor");
1096  tmp.add_source_location()=expr.source_location();
1097  expr.swap(tmp);
1098  return;
1099  }
1100 
1101  // The member operator will trigger template elaboration
1103 
1104  const typet &followed_op0_type=follow(op0.type());
1105 
1106  if(followed_op0_type.id()==ID_incomplete_struct ||
1107  followed_op0_type.id()==ID_incomplete_union)
1108  {
1110  error() << "error: member operator got incomplete type "
1111  << "on left hand side" << eom;
1112  throw 0;
1113  }
1114 
1115  if(followed_op0_type.id()!=ID_struct &&
1116  followed_op0_type.id()!=ID_union)
1117  {
1119  error() << "error: member operator requires struct/union type "
1120  << "on left hand side but got `"
1121  << to_string(followed_op0_type) << "'" << eom;
1122  throw 0;
1123  }
1124 
1125  const struct_union_typet &type=
1126  to_struct_union_type(followed_op0_type);
1127 
1128  irep_idt struct_identifier=type.get(ID_name);
1129 
1130  if(expr.find(ID_component_cpp_name).is_not_nil())
1131  {
1132  cpp_namet component_cpp_name=
1133  to_cpp_name(expr.find(ID_component_cpp_name));
1134 
1135  // go to the scope of the struct/union
1136  cpp_save_scopet save_scope(cpp_scopes);
1137  cpp_scopes.set_scope(struct_identifier);
1138 
1139  // resolve the member name in this scope
1140  cpp_typecheck_fargst new_fargs(fargs);
1141  new_fargs.add_object(op0);
1142 
1143  exprt symbol_expr=resolve(
1144  component_cpp_name,
1146  new_fargs);
1147 
1148  if(symbol_expr.id()==ID_dereference)
1149  {
1150  assert(symbol_expr.get_bool(ID_C_implicit));
1151  exprt tmp=symbol_expr.op0();
1152  symbol_expr.swap(tmp);
1153  }
1154 
1155  assert(symbol_expr.id()==ID_symbol ||
1156  symbol_expr.id()==ID_member ||
1157  symbol_expr.id()==ID_constant);
1158 
1159  // If it is a symbol or a constant, just return it!
1160  // Note: the resolver returns a symbol if the member
1161  // is static or if it is a constructor.
1162 
1163  if(symbol_expr.id()==ID_symbol)
1164  {
1165  if(symbol_expr.type().id()==ID_code &&
1166  symbol_expr.type().get(ID_return_type)==ID_constructor)
1167  {
1169  error() << "error: member `"
1170  << lookup(symbol_expr.get(ID_identifier)).base_name
1171  << "' is a constructor" << eom;
1172  throw 0;
1173  }
1174  else
1175  {
1176  // it must be a static component
1177  const struct_typet::componentt pcomp=
1178  type.get_component(to_symbol_expr(symbol_expr).get_identifier());
1179 
1180  if(pcomp.is_nil())
1181  {
1183  error() << "error: `"
1184  << symbol_expr.get(ID_identifier)
1185  << "' is not static member "
1186  << "of class `" << to_string(type) << "'"
1187  << eom;
1188  throw 0;
1189  }
1190  }
1191 
1192  expr=symbol_expr;
1193  return;
1194  }
1195  else if(symbol_expr.id()==ID_constant)
1196  {
1197  expr=symbol_expr;
1198  return;
1199  }
1200 
1201  const irep_idt component_name=symbol_expr.get(ID_component_name);
1202 
1203  expr.remove(ID_component_cpp_name);
1204  expr.set(ID_component_name, component_name);
1205  }
1206 
1207  const irep_idt &component_name=expr.get(ID_component_name);
1208 
1209  assert(component_name!="");
1210 
1211  exprt component;
1212  component.make_nil();
1213 
1214  assert(follow(expr.op0().type()).id()==ID_struct ||
1215  follow(expr.op0().type()).id()==ID_union);
1216 
1217  exprt member;
1218 
1219  if(get_component(expr.source_location(),
1220  expr.op0(),
1221  component_name,
1222  member))
1223  {
1224  // because of possible anonymous members
1225  expr.swap(member);
1226  }
1227  else
1228  {
1230  error() << "error: member `" << component_name
1231  << "' of `" << to_string(type)
1232  << "' not found" << eom;
1233  throw 0;
1234  }
1235 
1237 
1238  if(expr.type().id()==ID_code)
1239  {
1240  // Check if the function body has to be typechecked
1241  symbol_tablet::symbolst::iterator it=
1242  symbol_table.symbols.find(component_name);
1243 
1244  assert(it!=symbol_table.symbols.end());
1245 
1246  symbolt &func_symb=it->second;
1247 
1248  if(func_symb.value.id()=="cpp_not_typechecked")
1249  func_symb.value.set("is_used", true);
1250  }
1251 }
1252 
1254  exprt &expr,
1255  const cpp_typecheck_fargst &fargs)
1256 {
1257  assert(expr.id()==ID_ptrmember);
1258 
1259  if(expr.operands().size()!=1)
1260  {
1262  error() << "error: ptrmember operator expects one operand" << eom;
1263  throw 0;
1264  }
1265 
1266  add_implicit_dereference(expr.op0());
1267 
1268  if(expr.op0().type().id()!=ID_pointer)
1269  {
1271  error() << "error: ptrmember operator requires pointer type "
1272  << "on left hand side, but got `"
1273  << to_string(expr.op0().type()) << "'" << eom;
1274  throw 0;
1275  }
1276 
1277  exprt tmp;
1278  exprt &op=expr.op0();
1279 
1280  op.swap(tmp);
1281 
1282  op.id(ID_dereference);
1283  op.move_to_operands(tmp);
1286 
1287  expr.id(ID_member);
1288  typecheck_expr_member(expr, fargs);
1289 }
1290 
1292 {
1295 
1296  if(e.arguments().size() != 1)
1297  {
1299  error() << "cast expressions expect one operand" << eom;
1300  throw 0;
1301  }
1302 
1303  exprt &f_op=e.function();
1304  exprt &cast_op=e.arguments().front();
1305 
1306  add_implicit_dereference(cast_op);
1307 
1308  const irep_idt &id=
1309  f_op.get_sub().front().get(ID_identifier);
1310 
1311  if(f_op.get_sub().size()!=2 ||
1312  f_op.get_sub()[1].id()!=ID_template_args)
1313  {
1315  error() << id << " expects template argument" << eom;
1316  throw 0;
1317  }
1318 
1319  irept &template_arguments=f_op.get_sub()[1].add(ID_arguments);
1320 
1321  if(template_arguments.get_sub().size()!=1)
1322  {
1324  error() << id << " expects one template argument" << eom;
1325  throw 0;
1326  }
1327 
1328  irept &template_arg=template_arguments.get_sub().front();
1329 
1330  if(template_arg.id()!=ID_type &&
1331  template_arg.id()!="ambiguous")
1332  {
1334  error() << id << " expects a type as template argument" << eom;
1335  throw 0;
1336  }
1337 
1338  typet &type=static_cast<typet &>(
1339  template_arguments.get_sub().front().add(ID_type));
1340 
1341  typecheck_type(type);
1342 
1343  source_locationt source_location=expr.source_location();
1344 
1345  exprt new_expr;
1346  if(id==ID_const_cast)
1347  {
1348  if(!const_typecast(cast_op, type, new_expr))
1349  {
1351  error() << "type mismatch on const_cast:\n"
1352  << "operand type: `" << to_string(cast_op.type())
1353  << "'\n"
1354  << "cast type: `" << to_string(type) << "'" << eom;
1355  throw 0;
1356  }
1357  }
1358  else if(id==ID_dynamic_cast)
1359  {
1360  if(!dynamic_typecast(cast_op, type, new_expr))
1361  {
1363  error() << "type mismatch on dynamic_cast:\n"
1364  << "operand type: `" << to_string(cast_op.type())
1365  << "'\n"
1366  << "cast type: `" << to_string(type) << "'" << eom;
1367  throw 0;
1368  }
1369  }
1370  else if(id==ID_reinterpret_cast)
1371  {
1372  if(!reinterpret_typecast(cast_op, type, new_expr))
1373  {
1375  error() << "type mismatch on reinterpret_cast:\n"
1376  << "operand type: `" << to_string(cast_op.type())
1377  << "'\n"
1378  << "cast type: `" << to_string(type) << "'" << eom;
1379  throw 0;
1380  }
1381  }
1382  else if(id==ID_static_cast)
1383  {
1384  if(!static_typecast(cast_op, type, new_expr))
1385  {
1387  error() << "type mismatch on static_cast:\n"
1388  << "operand type: `" << to_string(cast_op.type())
1389  << "'\n"
1390  << "cast type: `" << to_string(type) << "'" << eom;
1391  throw 0;
1392  }
1393  }
1394  else
1395  assert(false);
1396 
1397  expr.swap(new_expr);
1398 }
1399 
1401  exprt &expr,
1402  const cpp_typecheck_fargst &fargs)
1403 {
1404  source_locationt source_location=
1405  to_cpp_name(expr).source_location();
1406 
1407  if(expr.get_sub().size()==1 &&
1408  expr.get_sub()[0].id()==ID_name)
1409  {
1410  const irep_idt identifier=expr.get_sub()[0].get(ID_identifier);
1411 
1412  if(identifier=="__sync_fetch_and_add" ||
1413  identifier=="__sync_fetch_and_sub" ||
1414  identifier=="__sync_fetch_and_or" ||
1415  identifier=="__sync_fetch_and_and" ||
1416  identifier=="__sync_fetch_and_xor" ||
1417  identifier=="__sync_fetch_and_nand" ||
1418  identifier=="__sync_add_and_fetch" ||
1419  identifier=="__sync_sub_and_fetch" ||
1420  identifier=="__sync_or_and_fetch" ||
1421  identifier=="__sync_and_and_fetch" ||
1422  identifier=="__sync_xor_and_fetch" ||
1423  identifier=="__sync_nand_and_fetch" ||
1424  identifier=="__sync_val_compare_and_swap" ||
1425  identifier=="__sync_lock_test_and_set" ||
1426  identifier=="__sync_lock_release")
1427  {
1428  // These are polymorphic, see
1429  // http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html
1430 
1431  // adjust return type of function to match pointer subtype
1432  if(fargs.operands.empty())
1433  {
1434  error().source_location=source_location;
1435  error() << "__sync_* primitives take as least one argument"
1436  << eom;
1437  throw 0;
1438  }
1439 
1440  const exprt &ptr_arg=fargs.operands.front();
1441 
1442  if(ptr_arg.type().id()!=ID_pointer)
1443  {
1444  error().source_location=source_location;
1445  error() << "__sync_* primitives take a pointer as first argument"
1446  << eom;
1447  throw 0;
1448  }
1449 
1451  result.add_source_location()=source_location;
1452  result.set_identifier(identifier);
1453  code_typet t;
1454  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1455  t.make_ellipsis();
1456  t.return_type()=ptr_arg.type().subtype();
1457  result.type()=t;
1458  expr.swap(result);
1459  return;
1460  }
1461  else if(identifier=="__atomic_load_n")
1462  {
1463  // These are polymorphic
1464  // https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
1465  // type __atomic_load_n(type *ptr, int memorder)
1466 
1467  if(fargs.operands.size()!=2)
1468  {
1469  error().source_location=source_location;
1470  error() << identifier << " expects two arguments" << eom;
1471  throw 0;
1472  }
1473 
1474  const exprt &ptr_arg=fargs.operands.front();
1475 
1476  if(ptr_arg.type().id()!=ID_pointer)
1477  {
1478  error().source_location=source_location;
1479  error() << identifier << " takes a pointer as first argument"
1480  << eom;
1481  throw 0;
1482  }
1483 
1485  result.add_source_location()=source_location;
1486  result.set_identifier(identifier);
1487  code_typet t;
1488  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1490  t.return_type()=ptr_arg.type().subtype();
1491  result.type()=t;
1492  expr.swap(result);
1493  return;
1494  }
1495  else if(identifier=="__atomic_store_n")
1496  {
1497  // These are polymorphic
1498  // https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
1499  // void __atomic_store_n(type *ptr, type val, int memorder)
1500 
1501  if(fargs.operands.size()!=3)
1502  {
1503  error().source_location=source_location;
1504  error() << identifier << " expects three arguments" << eom;
1505  throw 0;
1506  }
1507 
1508  const exprt &ptr_arg=fargs.operands.front();
1509 
1510  if(ptr_arg.type().id()!=ID_pointer)
1511  {
1512  error().source_location=source_location;
1513  error() << identifier << " takes a pointer as first argument"
1514  << eom;
1515  throw 0;
1516  }
1517 
1519  result.add_source_location()=source_location;
1520  result.set_identifier(identifier);
1521  code_typet t;
1522  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1523  t.parameters().push_back(
1524  code_typet::parametert(ptr_arg.type().subtype()));
1526  t.return_type()=empty_typet();
1527  result.type()=t;
1528  expr.swap(result);
1529  return;
1530  }
1531  else if(identifier=="__atomic_exchange_n")
1532  {
1533  // These are polymorphic
1534  // https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
1535  // type __atomic_exchange_n(type *ptr, type val, int memorder)
1536 
1537  if(fargs.operands.size()!=3)
1538  {
1539  error().source_location=source_location;
1540  error() << identifier << " expects three arguments" << eom;
1541  throw 0;
1542  }
1543 
1544  const exprt &ptr_arg=fargs.operands.front();
1545 
1546  if(ptr_arg.type().id()!=ID_pointer)
1547  {
1548  error().source_location=source_location;
1549  error() << identifier << " takes a pointer as first argument"
1550  << eom;
1551  throw 0;
1552  }
1553 
1555  result.add_source_location()=source_location;
1556  result.set_identifier(identifier);
1557  code_typet t;
1558  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1559  t.parameters().push_back(
1560  code_typet::parametert(ptr_arg.type().subtype()));
1562  t.return_type()=ptr_arg.type().subtype();
1563  result.type()=t;
1564  expr.swap(result);
1565  return;
1566  }
1567  else if(identifier=="__atomic_load" ||
1568  identifier=="__atomic_store")
1569  {
1570  // void __atomic_load(type *ptr, type *ret, int memorder)
1571  // void __atomic_store(type *ptr, type *val, int memorder)
1572 
1573  if(fargs.operands.size()!=3)
1574  {
1575  error().source_location=source_location;
1576  error() << identifier << " expects three arguments" << eom;
1577  throw 0;
1578  }
1579 
1580  if(fargs.operands[0].type().id()!=ID_pointer)
1581  {
1582  error().source_location=source_location;
1583  error() << identifier << " takes a pointer as first argument"
1584  << eom;
1585  throw 0;
1586  }
1587 
1588  if(fargs.operands[1].type().id()!=ID_pointer)
1589  {
1590  error().source_location=source_location;
1591  error() << identifier << " takes a pointer as second argument"
1592  << eom;
1593  throw 0;
1594  }
1595 
1596  const exprt &ptr_arg=fargs.operands.front();
1597 
1599  result.add_source_location()=source_location;
1600  result.set_identifier(identifier);
1601  code_typet t;
1602  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1603  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1605  t.return_type()=empty_typet();
1606  result.type()=t;
1607  expr.swap(result);
1608  return;
1609  }
1610  else if(identifier=="__atomic_exchange")
1611  {
1612  // void __atomic_exchange(type *ptr, type *val, type *ret, int memorder)
1613 
1614  if(fargs.operands.size()!=4)
1615  {
1616  error().source_location=source_location;
1617  error() << identifier << " expects four arguments" << eom;
1618  throw 0;
1619  }
1620 
1621  if(fargs.operands[0].type().id()!=ID_pointer)
1622  {
1623  error().source_location=source_location;
1624  error() << identifier << " takes a pointer as first argument"
1625  << eom;
1626  throw 0;
1627  }
1628 
1629  if(fargs.operands[1].type().id()!=ID_pointer)
1630  {
1631  error().source_location=source_location;
1632  error() << identifier << " takes a pointer as second argument"
1633  << eom;
1634  throw 0;
1635  }
1636 
1637  if(fargs.operands[2].type().id()!=ID_pointer)
1638  {
1639  error().source_location=source_location;
1640  error() << identifier << " takes a pointer as third argument"
1641  << eom;
1642  throw 0;
1643  }
1644 
1645  const exprt &ptr_arg=fargs.operands.front();
1646 
1648  result.add_source_location()=source_location;
1649  result.set_identifier(identifier);
1650  code_typet t;
1651  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1652  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1653  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1655  t.return_type()=empty_typet();
1656  result.type()=t;
1657  expr.swap(result);
1658  return;
1659  }
1660  else if(identifier=="__atomic_compare_exchange_n" ||
1661  identifier=="__atomic_compare_exchange")
1662  {
1663  // bool __atomic_compare_exchange_n(type *ptr, type *expected, type
1664  // desired, bool weak, int success_memorder, int failure_memorder)
1665  // bool __atomic_compare_exchange(type *ptr, type *expected, type
1666  // *desired, bool weak, int success_memorder, int failure_memorder)
1667 
1668  if(fargs.operands.size()!=6)
1669  {
1670  error().source_location=source_location;
1671  error() << identifier << " expects six arguments" << eom;
1672  throw 0;
1673  }
1674 
1675  if(fargs.operands[0].type().id()!=ID_pointer)
1676  {
1677  error().source_location=source_location;
1678  error() << identifier << " takes a pointer as first argument"
1679  << eom;
1680  throw 0;
1681  }
1682 
1683  if(fargs.operands[1].type().id()!=ID_pointer)
1684  {
1685  error().source_location=source_location;
1686  error() << identifier << " takes a pointer as second argument"
1687  << eom;
1688  throw 0;
1689  }
1690 
1691  if(identifier=="__atomic_compare_exchange" &&
1692  fargs.operands[2].type().id()!=ID_pointer)
1693  {
1694  error().source_location=source_location;
1695  error() << identifier << " takes a pointer as third argument"
1696  << eom;
1697  throw 0;
1698  }
1699 
1700  const exprt &ptr_arg=fargs.operands.front();
1701 
1703  result.add_source_location()=source_location;
1704  result.set_identifier(identifier);
1705  code_typet t;
1706  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1707  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1708 
1709  if(identifier=="__atomic_compare_exchange")
1710  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1711  else
1712  t.parameters().push_back(
1713  code_typet::parametert(ptr_arg.type().subtype()));
1714 
1715  t.parameters().push_back(code_typet::parametert(c_bool_type()));
1718  t.return_type()=c_bool_type();
1719  result.type()=t;
1720  expr.swap(result);
1721  return;
1722  }
1723  else if(identifier=="__atomic_add_fetch" ||
1724  identifier=="__atomic_sub_fetch" ||
1725  identifier=="__atomic_and_fetch" ||
1726  identifier=="__atomic_xor_fetch" ||
1727  identifier=="__atomic_or_fetch" ||
1728  identifier=="__atomic_nand_fetch")
1729  {
1730  if(fargs.operands.size()!=3)
1731  {
1732  error().source_location=source_location;
1733  error() << "__atomic_*_fetch primitives take three arguments"
1734  << eom;
1735  throw 0;
1736  }
1737 
1738  const exprt &ptr_arg=fargs.operands.front();
1739 
1740  if(ptr_arg.type().id()!=ID_pointer)
1741  {
1742  error().source_location=source_location;
1743  error() << "__atomic_*_fetch primitives take pointer as first argument"
1744  << eom;
1745  throw 0;
1746  }
1747 
1749  result.add_source_location()=source_location;
1750  result.set_identifier(identifier);
1751  code_typet t;
1752  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1753  t.make_ellipsis();
1754  t.return_type()=ptr_arg.type().subtype();
1755  result.type()=t;
1756  expr.swap(result);
1757  return;
1758  }
1759  else if(identifier=="__atomic_fetch_add" ||
1760  identifier=="__atomic_fetch_sub" ||
1761  identifier=="__atomic_fetch_and" ||
1762  identifier=="__atomic_fetch_xor" ||
1763  identifier=="__atomic_fetch_or" ||
1764  identifier=="__atomic_fetch_nand")
1765  {
1766  if(fargs.operands.size()!=3)
1767  {
1768  error().source_location=source_location;
1769  error() << "__atomic_fetch_* primitives take three arguments"
1770  << eom;
1771  throw 0;
1772  }
1773 
1774  const exprt &ptr_arg=fargs.operands.front();
1775 
1776  if(ptr_arg.type().id()!=ID_pointer)
1777  {
1778  error().source_location=source_location;
1779  error() << "__atomic_fetch_* primitives take pointer as first argument"
1780  << eom;
1781  throw 0;
1782  }
1783 
1785  result.add_source_location()=source_location;
1786  result.set_identifier(identifier);
1787  code_typet t;
1788  t.parameters().push_back(code_typet::parametert(ptr_arg.type()));
1789  t.make_ellipsis();
1790  t.return_type()=ptr_arg.type().subtype();
1791  result.type()=t;
1792  expr.swap(result);
1793  return;
1794  }
1795  else if(identifier=="__atomic_test_and_set")
1796  {
1797  }
1798  else if(identifier=="__atomic_clear")
1799  {
1800  }
1801  else if(identifier=="__atomic_thread_fence")
1802  {
1803  }
1804  else if(identifier=="__atomic_signal_fence")
1805  {
1806  }
1807  else if(identifier=="__atomic_always_lock_free")
1808  {
1809  }
1810  else if(identifier=="__atomic_is_lock_free")
1811  {
1812  }
1813  }
1814 
1815  for(std::size_t i=0; i<expr.get_sub().size(); i++)
1816  {
1817  if(expr.get_sub()[i].id()==ID_cpp_name)
1818  {
1819  typet &type=static_cast<typet &>(expr.get_sub()[i]);
1820  typecheck_type(type);
1821 
1822  std::string tmp="("+cpp_type2name(type)+")";
1823 
1824  typet name(ID_name);
1825  name.set(ID_identifier, tmp);
1826  name.add_source_location()=source_location;
1827 
1828  type=name;
1829  }
1830  }
1831 
1832  if(expr.get_sub().size()>=1 &&
1833  expr.get_sub().front().id()==ID_name)
1834  {
1835  const irep_idt &id=expr.get_sub().front().get(ID_identifier);
1836 
1837  if(id==ID_const_cast ||
1838  id==ID_dynamic_cast ||
1839  id==ID_reinterpret_cast ||
1840  id==ID_static_cast)
1841  {
1842  expr.id("cast_expression");
1843  return;
1844  }
1845  }
1846 
1847  exprt symbol_expr=
1848  resolve(
1849  to_cpp_name(expr),
1851  fargs);
1852 
1853  // we want VAR
1854  assert(symbol_expr.id()!=ID_type);
1855 
1856  if(symbol_expr.id()==ID_member)
1857  {
1858  if(symbol_expr.operands().empty() ||
1859  symbol_expr.op0().is_nil())
1860  {
1861  if(symbol_expr.type().get(ID_return_type)!=ID_constructor)
1862  {
1864  {
1865  if(symbol_expr.type().id()!=ID_code)
1866  {
1867  error().source_location=source_location;
1868  error() << "object missing" << eom;
1869  throw 0;
1870  }
1871 
1872  // may still be good for address of
1873  }
1874  else
1875  {
1876  // Try again
1877  exprt ptrmem(ID_ptrmember);
1878  ptrmem.operands().push_back(
1880 
1881  ptrmem.add(ID_component_cpp_name)=expr;
1882 
1883  ptrmem.add_source_location()=source_location;
1884  typecheck_expr_ptrmember(ptrmem, fargs);
1885  symbol_expr.swap(ptrmem);
1886  }
1887  }
1888  }
1889  }
1890 
1891  symbol_expr.add_source_location()=source_location;
1892  expr=symbol_expr;
1893 
1894  if(expr.id()==ID_symbol)
1896 
1898 }
1899 
1901 {
1902  if(is_reference(expr.type()))
1903  {
1904  // add implicit dereference
1905  exprt tmp(ID_dereference, expr.type().subtype());
1906  tmp.set(ID_C_implicit, true);
1907  tmp.add_source_location()=expr.source_location();
1908  tmp.move_to_operands(expr);
1909  tmp.set(ID_C_lvalue, true);
1910  expr.swap(tmp);
1911  }
1912 }
1913 
1916 {
1917  // For virtual functions, it is important to check whether
1918  // the function name is qualified. If it is qualified, then
1919  // the call is not virtual.
1920  bool is_qualified=false;
1921 
1922  if(expr.function().id()==ID_member ||
1923  expr.function().id()==ID_ptrmember)
1924  {
1925  if(expr.function().get(ID_component_cpp_name)==ID_cpp_name)
1926  {
1927  const cpp_namet &cpp_name=
1928  to_cpp_name(expr.function().find(ID_component_cpp_name));
1929  is_qualified=cpp_name.is_qualified();
1930  }
1931  }
1932  else if(expr.function().id()==ID_cpp_name)
1933  {
1934  const cpp_namet &cpp_name=to_cpp_name(expr.function());
1935  is_qualified=cpp_name.is_qualified();
1936  }
1937 
1938  // Backup of the original operand
1939  exprt op0=expr.function();
1940 
1941  // now do the function -- this has been postponed
1943 
1944  if(expr.function().id()=="pod_constructor")
1945  {
1946  assert(expr.function().type().id()==ID_code);
1947 
1948  // This must be a POD.
1949  const typet &pod=to_code_type(expr.function().type()).return_type();
1950  assert(cpp_is_pod(pod));
1951 
1952  // These aren't really function calls, but either conversions or
1953  // initializations.
1954  if(expr.arguments().empty())
1955  {
1956  // create temporary object
1957  exprt tmp_object_expr(ID_side_effect, pod);
1958  tmp_object_expr.set(ID_statement, ID_temporary_object);
1959  tmp_object_expr.set(ID_C_lvalue, true);
1960  tmp_object_expr.set(ID_mode, ID_cpp);
1961  tmp_object_expr.add_source_location()=expr.source_location();
1962  expr.swap(tmp_object_expr);
1963  }
1964  else if(expr.arguments().size()==1)
1965  {
1966  exprt typecast("explicit-typecast");
1967  typecast.type()=pod;
1968  typecast.add_source_location()=expr.source_location();
1969  typecast.copy_to_operands(expr.arguments().front());
1971  expr.swap(typecast);
1972  }
1973  else
1974  {
1976  error() << "zero or one argument expected" << eom;
1977  throw 0;
1978  }
1979 
1980  return;
1981  }
1982  else if(expr.function().id()=="cast_expression")
1983  {
1984  // These are not really function calls,
1985  // but usually just type adjustments.
1986  typecheck_cast_expr(expr);
1988  return;
1989  }
1990  else if(expr.function().id()=="cpp_dummy_destructor")
1991  {
1992  // these don't do anything, e.g., (char*)->~char()
1993  expr.set(ID_statement, ID_skip);
1994  expr.type()=empty_typet();
1995  return;
1996  }
1997 
1998  // look at type of function
1999 
2000  follow_symbol(expr.function().type());
2001 
2002  if(expr.function().type().id()==ID_pointer)
2003  {
2004  if(expr.function().type().find("to-member").is_not_nil())
2005  {
2006  const exprt &bound=
2007  static_cast<const exprt &>(expr.function().type().find("#bound"));
2008 
2009  if(bound.is_nil())
2010  {
2012  error() << "pointer-to-member not bound" << eom;
2013  throw 0;
2014  }
2015 
2016  // add `this'
2017  assert(bound.type().id()==ID_pointer);
2018  expr.arguments().insert(expr.arguments().begin(), bound);
2019 
2020  // we don't need the object any more
2021  expr.function().type().remove("#bound");
2022  }
2023 
2024  // do implicit dereference
2025  if(expr.function().id()==ID_address_of &&
2026  expr.function().operands().size()==1)
2027  {
2028  exprt tmp;
2029  tmp.swap(expr.function().op0());
2030  expr.function().swap(tmp);
2031  }
2032  else
2033  {
2034  assert(expr.function().type().id()==ID_pointer);
2035  exprt tmp(ID_dereference, expr.function().type().subtype());
2036  tmp.add_source_location()=expr.op0().source_location();
2037  tmp.move_to_operands(expr.function());
2038  expr.function().swap(tmp);
2039  }
2040 
2041  if(expr.function().type().id()!=ID_code)
2042  {
2044  error() << "expecting code as argument" << eom;
2045  throw 0;
2046  }
2047  }
2048  else if(expr.function().type().id()==ID_code)
2049  {
2050  if(expr.function().type().get_bool("#is_virtual") &&
2051  !is_qualified)
2052  {
2053  exprt vtptr_member;
2054  if(op0.id()==ID_member || op0.id()==ID_ptrmember)
2055  {
2056  vtptr_member.id(op0.id());
2057  vtptr_member.move_to_operands(op0.op0());
2058  }
2059  else
2060  {
2061  vtptr_member.id(ID_ptrmember);
2062  exprt this_expr("cpp-this");
2063  vtptr_member.move_to_operands(this_expr);
2064  }
2065 
2066  // get the virtual table
2067  typet this_type=
2068  to_code_type(expr.function().type()).parameters().front().type();
2069  irep_idt vtable_name=
2070  this_type.subtype().get_string(ID_identifier) +"::@vtable_pointer";
2071 
2072  const struct_typet &vt_struct=
2073  to_struct_type(follow(this_type.subtype()));
2074 
2075  const struct_typet::componentt &vt_compo=
2076  vt_struct.get_component(vtable_name);
2077 
2078  assert(vt_compo.is_not_nil());
2079 
2080  vtptr_member.set(ID_component_name, vtable_name);
2081 
2082  // look for the right entry
2083  irep_idt vtentry_component_name=
2084  vt_compo.type().subtype().get_string(ID_identifier)+"::"+
2085  expr.function().type().get_string("#virtual_name");
2086 
2087  exprt vtentry_member(ID_ptrmember);
2088  vtentry_member.copy_to_operands(vtptr_member);
2089  vtentry_member.set(ID_component_name, vtentry_component_name);
2090  typecheck_expr(vtentry_member);
2091 
2092  assert(vtentry_member.type().id()==ID_pointer);
2093 
2094  {
2095  exprt tmp(ID_dereference, vtentry_member.type().subtype());
2096  tmp.add_source_location()=expr.op0().source_location();
2097  tmp.move_to_operands(vtentry_member);
2098  vtentry_member.swap(tmp);
2099  }
2100 
2101  // Typecheck the expression as if it was not virtual
2102  // (add the this pointer)
2103 
2104  expr.type()=
2105  to_code_type(expr.function().type()).return_type();
2106 
2108 
2109  // Let's make the call virtual
2110  expr.function().swap(vtentry_member);
2111 
2114  return;
2115  }
2116  }
2117  else if(expr.function().type().id()==ID_struct)
2118  {
2119  irept name(ID_name);
2120  name.set(ID_identifier, "operator()");
2121  name.set(ID_C_source_location, expr.source_location());
2122 
2123  cpp_namet cppname;
2124  cppname.get_sub().push_back(name);
2125 
2126  exprt member(ID_member);
2127  member.add(ID_component_cpp_name)=cppname;
2128 
2129  member.move_to_operands(op0);
2130 
2131  expr.function().swap(member);
2133 
2134  return;
2135  }
2136  else
2137  {
2139  error() << "function call expects function or function "
2140  << "pointer as argument, but got `"
2141  << to_string(expr.op0().type()) << "'" << eom;
2142  throw 0;
2143  }
2144 
2145  expr.type()=
2146  to_code_type(expr.function().type()).return_type();
2147 
2148  if(expr.type().id()==ID_constructor)
2149  {
2150  assert(expr.function().id() == ID_symbol);
2151 
2152  const code_typet::parameterst &parameters=
2153  to_code_type(expr.function().type()).parameters();
2154 
2155  assert(parameters.size()>=1);
2156 
2157  const typet &this_type=parameters[0].type();
2158 
2159  // change type from 'constructor' to object type
2160  expr.type()=this_type.subtype();
2161 
2162  // create temporary object
2163  exprt tmp_object_expr(ID_side_effect, this_type.subtype());
2164  tmp_object_expr.set(ID_statement, ID_temporary_object);
2165  tmp_object_expr.set(ID_C_lvalue, true);
2166  tmp_object_expr.set(ID_mode, ID_cpp);
2167  tmp_object_expr.add_source_location()=expr.source_location();
2168 
2169  exprt member;
2170 
2171  exprt new_object("new_object", tmp_object_expr.type());
2172  new_object.set(ID_C_lvalue, true);
2173 
2174  assert(follow(tmp_object_expr.type()).id()==ID_struct);
2175 
2177  new_object,
2178  expr.function().get(ID_identifier),
2179  member);
2180 
2181  // special case for the initialization of parents
2182  if(member.get_bool("#not_accessible"))
2183  {
2184  assert(member.get(ID_C_access)!="");
2185  tmp_object_expr.set("#not_accessible", true);
2186  tmp_object_expr.set(ID_C_access, member.get(ID_C_access));
2187  }
2188 
2189  // the constructor is being used, so make sure the destructor
2190  // will be available
2191  {
2192  // find name of destructor
2193  const struct_typet::componentst &components=
2194  to_struct_type(follow(tmp_object_expr.type())).components();
2195 
2196  for(struct_typet::componentst::const_iterator
2197  it=components.begin();
2198  it!=components.end();
2199  it++)
2200  {
2201  const typet &type=it->type();
2202 
2203  if(!it->get_bool(ID_from_base) &&
2204  type.id()==ID_code &&
2205  type.find(ID_return_type).id()==ID_destructor)
2206  {
2207  symbol_tablet::symbolst::iterator s_it=
2208  symbol_table.symbols.find(it->get(ID_name));
2209  assert(s_it!=symbol_table.symbols.end());
2210  add_method_body(&(s_it->second));
2211  break;
2212  }
2213  }
2214  }
2215 
2216  expr.function().swap(member);
2217 
2220 
2221  codet new_code(ID_expression);
2222  new_code.copy_to_operands(expr);
2223 
2224  tmp_object_expr.add(ID_initializer)=new_code;
2225  expr.swap(tmp_object_expr);
2226  return;
2227  }
2228 
2229  assert(expr.operands().size()==2);
2230 
2231  if(expr.function().id()==ID_member)
2233  else
2234  {
2235  // for the object of a method call,
2236  // we are willing to add an "address_of"
2237  // for the sake of operator overloading
2238 
2239  const irept::subt &arguments=
2240  expr.function().type().find(ID_arguments).get_sub();
2241 
2242  if(arguments.size()>=1 &&
2243  arguments.front().get(ID_C_base_name)==ID_this &&
2244  expr.arguments().size()>=1)
2245  {
2246  const exprt &argument=
2247  static_cast<const exprt &>(arguments.front());
2248 
2249  exprt &operand=expr.op1();
2250  assert(argument.type().id()==ID_pointer);
2251 
2252  if(operand.type().id()!=ID_pointer &&
2253  operand.type()==argument.type().subtype())
2254  {
2255  address_of_exprt tmp(operand, pointer_type(operand.type()));
2256  tmp.add_source_location()=operand.source_location();
2257  operand=tmp;
2258  }
2259  }
2260  }
2261 
2262  assert(expr.operands().size()==2);
2263 
2265 
2266  assert(expr.operands().size()==2);
2267 
2269 
2270  // we will deal with some 'special' functions here
2271  exprt tmp=do_special_functions(expr);
2272  if(tmp.is_not_nil())
2273  expr.swap(tmp);
2274 }
2275 
2280 {
2281  exprt &f_op=expr.function();
2282  const code_typet &code_type=to_code_type(f_op.type());
2283  const code_typet::parameterst &parameters=code_type.parameters();
2284 
2285  // do default arguments
2286 
2287  if(parameters.size()>expr.arguments().size())
2288  {
2289  std::size_t i=expr.arguments().size();
2290 
2291  for(; i<parameters.size(); i++)
2292  {
2293  if(!parameters[i].has_default_value())
2294  break;
2295 
2296  const exprt &value=parameters[i].default_value();
2297  expr.arguments().push_back(value);
2298  }
2299  }
2300 
2301  exprt::operandst::iterator arg_it=expr.arguments().begin();
2302  for(const auto &parameter : parameters)
2303  {
2304  if(parameter.get_bool("#call_by_value"))
2305  {
2306  assert(is_reference(parameter.type()));
2307 
2308  if(arg_it->id()!=ID_temporary_object)
2309  {
2310  // create a temporary for the parameter
2311 
2312  exprt arg("already_typechecked");
2313  arg.copy_to_operands(*arg_it);
2314 
2315  exprt temporary;
2316  new_temporary(
2317  arg_it->source_location(),
2318  parameter.type().subtype(),
2319  arg,
2320  temporary);
2321  arg_it->swap(temporary);
2322  }
2323  }
2324 
2325  ++arg_it;
2326  }
2327 
2329 }
2330 
2332  side_effect_exprt &expr)
2333 {
2334  const irep_idt &statement=expr.get(ID_statement);
2335 
2336  if(statement==ID_cpp_new ||
2337  statement==ID_cpp_new_array)
2338  {
2339  typecheck_expr_new(expr);
2340  }
2341  else if(statement==ID_cpp_delete ||
2342  statement==ID_cpp_delete_array)
2343  {
2344  typecheck_expr_delete(expr);
2345  }
2346  else if(statement==ID_preincrement ||
2347  statement==ID_predecrement ||
2348  statement==ID_postincrement ||
2349  statement==ID_postdecrement)
2350  {
2352  }
2353  else if(statement==ID_throw)
2354  {
2355  typecheck_expr_throw(expr);
2356  }
2357  else if(statement==ID_temporary_object)
2358  {
2359  // TODO
2360  }
2361  else
2363 }
2364 
2367 {
2368  assert(expr.operands().size()==2);
2369 
2370  assert(expr.function().id()==ID_member);
2371  assert(expr.function().operands().size()==1);
2372 
2373  // turn e.f(...) into xx::f(e, ...)
2374 
2375  exprt member_expr;
2376  member_expr.swap(expr.function());
2377 
2378  const symbolt &symbol=lookup(member_expr.get(ID_component_name));
2379  add_method_body(&(symbol_table.symbols.find(symbol.name)->second));
2380 
2381  // build new function expression
2382  exprt new_function(cpp_symbol_expr(symbol));
2383  new_function.add_source_location()=member_expr.source_location();
2384  expr.function().swap(new_function);
2385 
2386  if(!expr.function().type().get_bool("#is_static"))
2387  {
2388  const code_typet &func_type=to_code_type(symbol.type);
2389  typet this_type=func_type.parameters().front().type();
2390 
2391  // Special case. Make it a reference.
2392  assert(this_type.id()==ID_pointer);
2393  this_type.set(ID_C_reference, true);
2394  this_type.set("#this", true);
2395 
2396  if(expr.arguments().size()==func_type.parameters().size())
2397  {
2398  // this might be set up for base-class initialisation
2399  if(!base_type_eq(expr.arguments().front().type(),
2400  func_type.parameters().front().type(),
2401  *this))
2402  {
2403  implicit_typecast(expr.arguments().front(), this_type);
2404  assert(is_reference(expr.arguments().front().type()));
2405  expr.arguments().front().type().remove(ID_C_reference);
2406  }
2407  }
2408  else
2409  {
2410  exprt this_arg=member_expr.op0();
2411  implicit_typecast(this_arg, this_type);
2412  assert(is_reference(this_arg.type()));
2413  this_arg.type().remove(ID_C_reference);
2414  expr.arguments().insert(expr.arguments().begin(), this_arg);
2415  }
2416  }
2417 
2418  if(symbol.value.id()=="cpp_not_typechecked" &&
2419  !symbol.value.get_bool("is_used"))
2420  {
2421  symbol_table.symbols[symbol.name].value.set("is_used", true);
2422  }
2423 }
2424 
2426 {
2427  if(expr.operands().size()!=2)
2428  {
2430  error() << "assignment side effect expected to have two operands"
2431  << eom;
2432  throw 0;
2433  }
2434 
2435  typet type0=expr.op0().type();
2436 
2437  if(is_reference(type0))
2438  type0=type0.subtype();
2439 
2440  if(cpp_is_pod(type0))
2441  {
2442  // for structs we use the 'implicit assignment operator',
2443  // and therefore, it is allowed to assign to a rvalue struct.
2444  if(follow(type0).id()==ID_struct)
2445  expr.op0().set(ID_C_lvalue, true);
2446 
2448 
2449  // Note that in C++ (as opposed to C), the assignment yields
2450  // an lvalue!
2451  expr.set(ID_C_lvalue, true);
2452  return;
2453  }
2454 
2455  // It's a non-POD.
2456  // Turn into an operator call
2457 
2458  std::string strop="operator";
2459 
2460  const irep_idt statement=expr.get(ID_statement);
2461 
2462  if(statement==ID_assign)
2463  strop += "=";
2464  else if(statement==ID_assign_shl)
2465  strop += "<<=";
2466  else if(statement==ID_assign_shr)
2467  strop += ">>=";
2468  else if(statement==ID_assign_plus)
2469  strop += "+=";
2470  else if(statement==ID_assign_minus)
2471  strop += "-=";
2472  else if(statement==ID_assign_mult)
2473  strop += "*=";
2474  else if(statement==ID_assign_div)
2475  strop += "/=";
2476  else if(statement==ID_assign_bitand)
2477  strop += "&=";
2478  else if(statement==ID_assign_bitor)
2479  strop += "|=";
2480  else if(statement==ID_assign_bitxor)
2481  strop += "^=";
2482  else
2483  {
2485  error() << "bad assignment operator `" << statement << "'" << eom;
2486  throw 0;
2487  }
2488 
2489  cpp_namet cpp_name;
2490  cpp_name.get_sub().push_back(irept(ID_name));
2491  cpp_name.get_sub().front().set(ID_identifier, strop);
2492  cpp_name.get_sub().front().set(ID_C_source_location, expr.source_location());
2493 
2494  // expr.op0() is already typechecked
2495  exprt already_typechecked(ID_already_typechecked);
2496  already_typechecked.move_to_operands(expr.op0());
2497 
2498  exprt member(ID_member);
2499  member.set(ID_component_cpp_name, cpp_name);
2501 
2503  new_expr.function().swap(member);
2504  new_expr.arguments().push_back(expr.op1());
2505  new_expr.add_source_location()=expr.source_location();
2506 
2508 
2509  expr=new_expr;
2510 }
2511 
2513  side_effect_exprt &expr)
2514 {
2515  if(expr.operands().size()!=1)
2516  {
2518  error() << "statement " << expr.get_statement()
2519  << " expected to have one operand" << eom;
2520  throw 0;
2521  }
2522 
2523  add_implicit_dereference(expr.op0());
2524 
2525  typet tmp_type=follow(expr.op0().type());
2526 
2527  if(is_number(tmp_type) ||
2528  tmp_type.id()==ID_pointer)
2529  {
2530  // standard stuff
2532  return;
2533  }
2534 
2535  // Turn into an operator call
2536 
2537  std::string str_op="operator";
2538  bool post=false;
2539 
2540  if(expr.get(ID_statement)==ID_preincrement)
2541  str_op += "++";
2542  else if(expr.get(ID_statement)==ID_predecrement)
2543  str_op += "--";
2544  else if(expr.get(ID_statement)==ID_postincrement)
2545  {
2546  str_op += "++";
2547  post=true;
2548  }
2549  else if(expr.get(ID_statement)==ID_postdecrement)
2550  {
2551  str_op += "--";
2552  post=true;
2553  }
2554  else
2555  {
2557  error() << "bad assignment operator `"
2558  << expr.get_statement()
2559  << "'" << eom;
2560  throw 0;
2561  }
2562 
2563  cpp_namet cpp_name;
2564  cpp_name.get_sub().push_back(irept(ID_name));
2565  cpp_name.get_sub().front().set(ID_identifier, str_op);
2566  cpp_name.get_sub().front().set(ID_C_source_location, expr.source_location());
2567 
2568  exprt already_typechecked("already_typechecked");
2569  already_typechecked.move_to_operands(expr.op0());
2570 
2571  exprt member(ID_member);
2572  member.set(ID_component_cpp_name, cpp_name);
2574 
2576  new_expr.function().swap(member);
2577  new_expr.add_source_location()=expr.source_location();
2578 
2579  // the odd C++ way to denote the post-inc/dec operator
2580  if(post)
2581  new_expr.arguments().push_back(
2583 
2585  expr.swap(new_expr);
2586 }
2587 
2589 {
2590  if(expr.operands().size()!=1)
2591  {
2593  error() << "unary operator * expects one operand" << eom;
2594  throw 0;
2595  }
2596 
2597  exprt &op=expr.op0();
2598  const typet op_type=follow(op.type());
2599 
2600  if(op_type.id()==ID_pointer &&
2601  op_type.find("to-member").is_not_nil())
2602  {
2604  error() << "pointer-to-member must use "
2605  << "the .* or ->* operators" << eom;
2606  throw 0;
2607  }
2608 
2610 }
2611 
2613 {
2614  assert(expr.id()=="pointer-to-member");
2615  assert(expr.operands().size() == 2);
2616 
2617  if(expr.op1().type().id()!=ID_pointer
2618  || expr.op1().type().find("to-member").is_nil())
2619  {
2621  error() << "pointer-to-member expected" << eom;
2622  throw 0;
2623  }
2624 
2625  typet t0=expr.op0().type().id()==ID_pointer ?
2626  expr.op0().type().subtype(): expr.op0().type();
2627 
2628  typet t1((const typet&)expr.op1().type().find("to-member"));
2629 
2630  t0=follow(t0);
2631  t1=follow(t1);
2632 
2633  if(t0.id()!=ID_struct)
2634  {
2636  error() << "pointer-to-member type error" << eom;
2637  throw 0;
2638  }
2639 
2640  const struct_typet &from_struct=to_struct_type(t0);
2641  const struct_typet &to_struct=to_struct_type(t1);
2642 
2643  if(!subtype_typecast(from_struct, to_struct))
2644  {
2646  error() << "pointer-to-member type error" << eom;
2647  throw 0;
2648  }
2649 
2650  if(expr.op1().type().subtype().id()!=ID_code)
2651  {
2653  error() << "pointers to data member are not supported" << eom;
2654  throw 0;
2655  }
2656 
2657  typecheck_expr_main(expr.op1());
2658 
2659  if(expr.op0().type().id()!=ID_pointer)
2660  {
2661  if(expr.op0().id()==ID_dereference)
2662  {
2663  exprt tmp=expr.op0().op0();
2664  expr.op0().swap(tmp);
2665  }
2666  else
2667  {
2668  assert(expr.op0().get_bool(ID_C_lvalue));
2669  expr.op0()=address_of_exprt(expr.op0());
2670  }
2671  }
2672 
2673  exprt tmp(expr.op1());
2674  tmp.type().set("#bound", expr.op0());
2675  expr.swap(tmp);
2676  return;
2677 }
2678 
2680 {
2681  if(expr.id()==ID_symbol)
2682  {
2683  // Check if the function body has to be typechecked
2684  symbol_tablet::symbolst::iterator it=
2685  symbol_table.symbols.find(expr.get(ID_identifier));
2686 
2687  assert(it != symbol_table.symbols.end());
2688 
2689  symbolt &func_symb=it->second;
2690 
2691  if(func_symb.value.id()=="cpp_not_typechecked")
2692  func_symb.value.set("is_used", true);
2693  }
2694 
2696 }
2697 
2699 {
2700  bool override_constantness=
2701  expr.get_bool("#override_constantness");
2702 
2703  // We take care of an ambiguity in the C++ grammar.
2704  // Needs to be done before the operands!
2706 
2707  // cpp_name uses get_sub, which can get confused with expressions.
2708  if(expr.id()==ID_cpp_name)
2710  else
2711  {
2712  // This does the operands, and then calls typecheck_expr_main.
2714  }
2715 
2716  if(override_constantness)
2717  expr.type().set(ID_C_constant, false);
2718 }
2719 
2721 {
2722  // There is an ambiguity in the C++ grammar as follows:
2723  // (TYPENAME) + expr (typecast of unary plus) vs.
2724  // (expr) + expr (sum of two expressions)
2725  // Same issue with the operators & and - and *
2726 
2727  // We figure this out by resolving the type argument
2728  // and re-writing if needed
2729 
2730  if(expr.id()!="explicit-typecast")
2731  return;
2732 
2733  assert(expr.operands().size()==1);
2734 
2735  irep_idt op0_id=expr.op0().id();
2736 
2737  if(expr.type().id()==ID_cpp_name &&
2738  expr.op0().operands().size()==1 &&
2739  (op0_id==ID_unary_plus ||
2740  op0_id==ID_unary_minus ||
2741  op0_id==ID_address_of ||
2742  op0_id==ID_dereference))
2743  {
2744  exprt resolve_result=
2745  resolve(
2746  to_cpp_name(expr.type()),
2749 
2750  if(resolve_result.id()!=ID_type)
2751  {
2752  // need to re-write the expression
2753  // e.g., (ID) +expr -> ID+expr
2754  exprt new_binary_expr;
2755 
2756  new_binary_expr.operands().resize(2);
2757  new_binary_expr.op0().swap(expr.type());
2758  new_binary_expr.op1().swap(expr.op0().op0());
2759 
2760  if(op0_id==ID_unary_plus)
2761  new_binary_expr.id(ID_plus);
2762  else if(op0_id==ID_unary_minus)
2763  new_binary_expr.id(ID_minus);
2764  else if(op0_id==ID_address_of)
2765  new_binary_expr.id(ID_bitand);
2766  else if(op0_id==ID_dereference)
2767  new_binary_expr.id(ID_mult);
2768 
2769  new_binary_expr.add_source_location()=expr.op0().source_location();
2770  expr.swap(new_binary_expr);
2771  }
2772  }
2773 }
2774 
2776 {
2777  if(expr.operands().size()!=2)
2778  {
2780  error() << "operator `" << expr.id() << "' expects two operands"
2781  << eom;
2782  throw 0;
2783  }
2784 
2785  add_implicit_dereference(expr.op0());
2786  add_implicit_dereference(expr.op1());
2787 
2789 }
2790 
2792 {
2794 }
2795 
2797 {
2798  if(expr.operands().size()!=2)
2799  {
2801  error() << "comma operator expects two operands" << eom;
2802  throw 0;
2803  }
2804 
2805  if(follow(expr.op0().type()).id()==ID_struct)
2806  {
2807  // TODO: check if the comma operator has been overloaded!
2808  }
2809 
2811 }
2812 
2814 {
2816 }
side_effect_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
Definition: std_code.h:1083
void typecheck_function_expr(exprt &expr, const cpp_typecheck_fargst &fargs)
The type of an expression.
Definition: type.h:20
irep_idt name
The unique identifier.
Definition: symbol.h:46
void typecheck_expr_dereference(exprt &expr)
mstreamt & result()
Definition: message.h:233
const typet & follow(const typet &src) const
Definition: namespace.cpp:66
struct configt::ansi_ct ansi_c
virtual void typecheck_side_effect_assignment(side_effect_exprt &expr)
void typecheck_side_effect_function_call(side_effect_expr_function_callt &expr)
virtual bool lookup(const irep_idt &name, const symbolt *&symbol) const
Definition: namespace.cpp:139
BigInt mp_integer
Definition: mp_arith.h:19
Linking: Zero Initialization.
void typecheck_type(typet &type)
Base type of functions.
Definition: std_types.h:734
bool is_nil() const
Definition: irep.h:103
A generic base class for relations, i.e., binary predicates.
Definition: std_expr.h:568
bool is_not_nil() const
Definition: irep.h:104
pointer_typet pointer_type(const typet &subtype)
Definition: c_types.cpp:296
unsigned int_width
Definition: config.h:30
void new_temporary(const source_locationt &source_location, const typet &, const exprt::operandst &ops, exprt &temporary)
void typecheck_expr_member(exprt &expr)
virtual void typecheck_expr_index(exprt &expr)
void typecheck_expr_rel(binary_relation_exprt &expr)
exprt & op0()
Definition: expr.h:84
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:641
std::vector< irept > subt
Definition: irep.h:91
void add_implicit_dereference(exprt &expr)
static exprt collect_comma_expression(const exprt &src)
bool base_type_eq(const typet &type1, const typet &type2, const namespacet &ns)
Definition: base_type.cpp:270
bool static_typecast(const exprt &expr, const typet &type, exprt &new_expr, bool check_constantness=true)
bool has_base(const irep_idt &id) const
Definition: std_types.h:380
bool find_parent(const symbolt &symb, const irep_idt &base_name, irep_idt &identifier)
exprt::operandst operands
void copy_to_operands(const exprt &expr)
Definition: expr.cpp:61
irept cpp_exception_list(const typet &src, const namespacet &ns)
turns a type into a list of relevant exception IDs
cpp_namet & to_cpp_name(irept &cpp_name)
Definition: cpp_name.h:143
std::vector< componentt > componentst
Definition: std_types.h:240
void move_to_operands(exprt &expr)
Definition: expr.cpp:28
std::vector< parametert > parameterst
Definition: std_types.h:829
void typecheck_expr_function_identifier(exprt &expr)
void already_typechecked(irept &irep)
Definition: cpp_util.h:18
bool overloadable(const exprt &expr)
virtual void typecheck_code(codet &code)
exprt value
Initial value of symbol.
Definition: symbol.h:40
const componentst & components() const
Definition: std_types.h:242
The trinary if-then-else operator.
Definition: std_expr.h:2771
void explicit_typecast_ambiguity(exprt &expr)
typet & type()
Definition: expr.h:60
void typecheck_method_application(side_effect_expr_function_callt &expr)
void typecheck_expr_delete(exprt &expr)
void typecheck_expr_this(exprt &expr)
virtual void implicit_typecast(exprt &expr, const typet &type)
The proper Booleans.
Definition: std_types.h:33
Symbol table entry.This is a symbol in the symbol table, stored in an object of type symbol_tablet...
Definition: symbol.h:33
static mstreamt & eom(mstreamt &m)
Definition: message.h:193
Structure type.
Definition: std_types.h:296
bool standard_conversion_function_to_pointer(const exprt &expr, exprt &new_expr) const
Function-to-pointer conversion.
bool get_bool(const irep_namet &name) const
Definition: irep.cpp:240
configt config
Definition: config.cpp:21
void typecheck_expr_typecast(exprt &expr)
bool is_qualified() const
Definition: cpp_name.h:108
void typecheck_expr_binary_arithmetic(exprt &expr)
virtual void typecheck_expr(exprt &expr)
subt & get_sub()
Definition: irep.h:245
symbol_tablet & symbol_table
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a generic typet to a struct_union_typet.
Definition: std_types.h:277
void typecheck_expr_explicit_typecast(exprt &expr)
bool dynamic_typecast(const exprt &expr, const typet &type, exprt &new_expr)
void read(const typet &src)
void add_method_body(symbolt *_method_symbol)
const irep_idt & id() const
Definition: irep.h:189
exprt c_sizeof(const typet &src, const namespacet &ns)
Definition: c_sizeof.cpp:303
const source_locationt & source_location() const
Definition: cpp_name.h:72
void typecheck_expr_ptrmember(exprt &expr)
const array_typet & to_array_type(const typet &type)
Cast a generic typet to an array_typet.
Definition: std_types.h:946
void typecheck_function_call_arguments(side_effect_expr_function_callt &expr)
void elaborate_class_template(const typet &type)
elaborate class template instances
virtual void typecheck_expr_side_effect(side_effect_exprt &expr)
void typecheck_expr_explicit_constructor_call(exprt &expr)
The boolean constant true.
Definition: std_expr.h:3742
symbolst symbols
Definition: symbol_table.h:57
virtual void typecheck_expr_operands(exprt &expr)
A reference into the symbol table.
Definition: std_types.h:109
void typecheck_cast_expr(exprt &expr)
reference_typet reference_type(const typet &subtype)
Definition: c_types.cpp:301
struct operator_entryt operators[]
The pointer type.
Definition: std_types.h:1343
const source_locationt & find_source_location() const
Definition: expr.cpp:466
C++ Language Module.
source_locationt source_location
Definition: message.h:175
The empty type.
Definition: std_types.h:53
bool cpp_is_pod(const typet &type) const
Definition: cpp_is_pod.cpp:14
bool reinterpret_typecast(const exprt &expr, const typet &type, exprt &new_expr, bool check_constantness=true)
C++ Language Conversion.
virtual void typecheck_expr_binary_arithmetic(exprt &expr)
C++ Language Type Checking.
API to expression classes.
bool is_reference(const typet &type)
TO_BE_DOCUMENTED.
Definition: std_types.cpp:105
exprt & op1()
Definition: expr.h:87
const irep_idt & get(const irep_namet &name) const
Definition: irep.cpp:213
codet cpp_destructor(const source_locationt &source_location, const typet &type, const exprt &object)
std::string cpp_type2name(const typet &type)
virtual void typecheck_expr(exprt &expr)
Base class for tree-like data structures with sharing.
Definition: irep.h:87
#define forall_operands(it, expr)
Definition: expr.h:17
irep_idt class_identifier
Definition: cpp_id.h:76
void add_object(const exprt &expr)
C++ Language Type Checking.
void typecheck_expr_throw(exprt &expr)
bitvector_typet index_type()
Definition: c_types.cpp:15
void typecheck_side_effect_assignment(side_effect_exprt &expr)
void convert_pmop(exprt &expr)
Operator to return the address of an object.
Definition: std_expr.h:2593
void zero_initializer(const exprt &object, const typet &type, const source_locationt &source_location, exprt::operandst &ops)
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:87
The boolean constant false.
Definition: std_expr.h:3753
virtual void typecheck_expr_function_identifier(exprt &expr)
void typecheck_expr_trinary(if_exprt &expr)
const struct_typet & to_struct_type(const typet &type)
Cast a generic typet to a struct_typet.
Definition: std_types.h:317
void make_ellipsis()
Definition: std_types.h:819
exprt this_expr
Definition: cpp_id.h:77
virtual void typecheck_function_call_arguments(side_effect_expr_function_callt &expr)
cpp_scopet & set_scope(const irep_idt &identifier)
Definition: cpp_scopes.h:88
A function call side effect.
Definition: std_code.h:1052
bool const_typecast(const exprt &expr, const typet &type, exprt &new_expr)
bool get_component(const source_locationt &source_location, const exprt &object, const irep_idt &component_name, exprt &member)
void typecheck_expr_address_of(exprt &expr)
virtual exprt do_special_functions(side_effect_expr_function_callt &expr)
typet type
Type of symbol.
Definition: symbol.h:37
virtual void typecheck_expr_sizeof(exprt &expr)
void follow_symbol(irept &irep) const
Definition: namespace.cpp:43
API to type classes.
bool subtype_typecast(const struct_typet &from, const struct_typet &to) const
message_handlert & get_message_handler()
Definition: message.h:127
bool operator_is_overloaded(exprt &expr)
bool standard_conversion_lvalue_to_rvalue(const exprt &expr, exprt &new_expr) const
Lvalue-to-rvalue conversion.
Base type of C structs and unions, and C++ classes.
Definition: std_types.h:159
bool is_number(const typet &type)
Definition: type.cpp:24
exprt & index()
Definition: std_expr.h:1208
bool is_subset_of(const c_qualifierst &q) const
Definition: c_qualifiers.h:59
void typecheck_expr_comma(exprt &expr)
std::string type2cpp(const typet &type, const namespacet &ns)
Definition: expr2cpp.cpp:512
Base class for all expressions.
Definition: expr.h:46
const parameterst & parameters() const
Definition: std_types.h:841
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast a generic exprt to a symbol_exprt.
Definition: std_expr.h:202
cpp_scopet & current_scope()
Definition: cpp_scopes.h:33
source_locationt & add_source_location()
Definition: type.h:100
const source_locationt & source_location() const
Definition: expr.h:142
virtual void typecheck_expr_dereference(exprt &expr)
irept & add(const irep_namet &name)
Definition: irep.cpp:306
virtual std::string to_string(const typet &type)
const std::string & get_string(const irep_namet &name) const
Definition: irep.h:202
const code_typet & to_code_type(const typet &type)
Cast a generic typet to a code_typet.
Definition: std_types.h:884
exprt::operandst & arguments()
Definition: std_code.h:1071
void make_nil()
Definition: irep.h:243
void swap(irept &irep)
Definition: irep.h:231
void typecheck_expr_side_effect(side_effect_exprt &expr)
mstreamt & error()
Definition: message.h:223
source_locationt & add_source_location()
Definition: expr.h:147
void typecheck_expr_main(exprt &expr)
Called after the operands are done.
bool standard_conversion_array_to_pointer(const exprt &expr, exprt &new_expr) const
Array-to-pointer conversion.
Expression to hold a symbol (variable)
Definition: std_expr.h:82
exprt & op2()
Definition: expr.h:90
virtual void typecheck_expr_rel(binary_relation_exprt &expr)
dstringt irep_idt
Definition: irep.h:32
A statement in a programming language.
Definition: std_code.h:19
signedbv_typet signed_int_type()
Definition: c_types.cpp:29
void typecheck_expr_cpp_name(exprt &expr, const cpp_typecheck_fargst &fargs)
exprt cpp_symbol_expr(const symbolt &symbol)
Definition: cpp_util.cpp:14
void remove(const irep_namet &name)
Definition: irep.cpp:270
void typecheck_side_effect_inc_dec(side_effect_exprt &expr)
Base Type Computation.
const typet & subtype() const
Definition: type.h:31
virtual void typecheck_expr_address_of(exprt &expr)
virtual void typecheck_expr_comma(exprt &expr)
C++ class type.
Definition: std_types.h:334
An expression containing a side effect.
Definition: std_code.h:997
void typecheck_expr_sizeof(exprt &expr)
bool implicit_conversion_sequence(const exprt &expr, const typet &type, exprt &new_expr, unsigned &rank)
implicit conversion sequence
virtual void typecheck_expr_main(exprt &expr)
operandst & operands()
Definition: expr.h:70
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
void typecheck_expr_index(exprt &expr)
typet c_bool_type()
Definition: c_types.cpp:107
bool empty() const
Definition: dstring.h:61
exprt & array()
Definition: std_expr.h:1198
const irept & find(const irep_namet &name) const
Definition: irep.cpp:285
const typet & return_type() const
Definition: std_types.h:831
codet cpp_constructor(const source_locationt &source_location, const exprt &object, const exprt::operandst &operands)
void typecheck_expr_new(exprt &expr)
void set(const irep_namet &name, const irep_idt &value)
Definition: irep.h:214
const componentt & get_component(const irep_idt &component_name) const
Definition: std_types.cpp:51
const irep_idt & get_statement() const
Definition: std_code.h:1012
#define forall_irep(it, irep)
Definition: irep.h:62
array index operator
Definition: std_expr.h:1170
cpp_scopest cpp_scopes
const class_typet & to_class_type(const typet &type)
Cast a generic typet to a class_typet.
Definition: std_types.h:407