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