CBMC
c_typecheck_code.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: C Language Type Checking
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include <util/c_types.h>
13 #include <util/config.h>
14 #include <util/cprover_prefix.h>
15 #include <util/expr_util.h>
16 #include <util/range.h>
17 #include <util/string_constant.h>
18 #include <util/symbol_table_base.h>
19 
20 #include "ansi_c_declaration.h"
21 #include "c_expr.h"
22 #include "c_typecheck_base.h"
23 
25 {
27 }
28 
30 {
31  if(code.id()!=ID_code)
32  {
34  error() << "expected code, got " << code.pretty() << eom;
35  throw 0;
36  }
37 
38  code.type() = empty_typet();
39 
40  const irep_idt &statement=code.get_statement();
41 
42  if(statement==ID_expression)
44  else if(statement==ID_label)
46  else if(statement==ID_switch_case)
48  else if(statement==ID_gcc_switch_case_range)
50  else if(statement==ID_block)
52  else if(statement==ID_decl_block)
53  {
54  }
55  else if(statement==ID_ifthenelse)
57  else if(statement==ID_while)
59  else if(statement==ID_dowhile)
61  else if(statement==ID_for)
62  typecheck_for(code);
63  else if(statement==ID_switch)
64  typecheck_switch(code);
65  else if(statement==ID_break)
66  typecheck_break(code);
67  else if(statement==ID_goto)
69  else if(statement==ID_gcc_computed_goto)
71  else if(statement==ID_continue)
72  typecheck_continue(code);
73  else if(statement==ID_return)
75  else if(statement==ID_decl)
76  typecheck_decl(code);
77  else if(statement==ID_assign)
78  typecheck_assign(code);
79  else if(statement==ID_skip)
80  {
81  }
82  else if(statement==ID_asm)
84  else if(statement==ID_start_thread)
86  else if(statement==ID_gcc_local_label)
88  else if(statement==ID_msc_try_finally)
89  {
90  PRECONDITION(code.operands().size() == 2);
91  typecheck_code(to_code(code.op0()));
92  typecheck_code(to_code(code.op1()));
93  }
94  else if(statement==ID_msc_try_except)
95  {
96  PRECONDITION(code.operands().size() == 3);
97  typecheck_code(to_code(code.op0()));
98  typecheck_expr(code.op1());
99  typecheck_code(to_code(code.op2()));
100  }
101  else if(statement==ID_msc_leave)
102  {
103  // fine as is, but should check that we
104  // are in a 'try' block
105  }
106  else if(statement==ID_static_assert)
107  {
108  PRECONDITION(code.operands().size() == 2);
109 
110  typecheck_expr(code.op0());
111  typecheck_expr(code.op1());
112 
113  implicit_typecast_bool(code.op0());
114  make_constant(code.op0());
115 
116  if(code.op0().is_false())
117  {
118  // failed
120  error() << "static assertion failed";
121  if(code.op1().id() == ID_string_constant)
122  error() << ": " << to_string_constant(code.op1()).value();
123  error() << eom;
124  throw 0;
125  }
126  }
127  else if(statement==ID_CPROVER_try_catch ||
128  statement==ID_CPROVER_try_finally)
129  {
130  PRECONDITION(code.operands().size() == 2);
131  typecheck_code(to_code(code.op0()));
132  typecheck_code(to_code(code.op1()));
133  }
134  else if(statement==ID_CPROVER_throw)
135  {
136  PRECONDITION(code.operands().empty());
137  }
138  else if(statement==ID_assume ||
139  statement==ID_assert)
140  {
141  // These are not generated by the C/C++ parsers,
142  // but we allow them for the benefit of other users
143  // of the typechecker.
144  PRECONDITION(code.operands().size() == 1);
145  typecheck_expr(code.op0());
146  }
147  else
148  {
150  error() << "unexpected statement: " << statement << eom;
151  throw 0;
152  }
153 }
154 
156 {
157  const irep_idt flavor = code.get_flavor();
158 
159  if(flavor==ID_gcc)
160  {
161  // These have 5 operands.
162  // The first operand is a string.
163  // Operands 1, 2, 3, 4 are lists of expressions.
164 
165  // Operand 1: OutputOperands
166  // Operand 2: InputOperands
167  // Operand 3: Clobbers
168  // Operand 4: GotoLabels
169 
170  auto &code_asm_gcc = to_code_asm_gcc(code);
171 
172  typecheck_expr(code_asm_gcc.asm_text());
173 
174  // the operands are lists of expressions
175  for(auto &op : ranget<exprt::operandst::iterator>(
176  code_asm_gcc.operands().begin() + 1, code_asm_gcc.operands().end()))
177  {
178  for(auto &expr : op.operands())
179  typecheck_expr(expr);
180  }
181  }
182  else if(flavor==ID_msc)
183  {
184  PRECONDITION(code.operands().size() == 1);
185  typecheck_expr(code.op0());
186  }
187 }
188 
190 {
191  if(code.operands().size()!=2)
192  {
194  error() << "assignment statement expected to have two operands"
195  << eom;
196  throw 0;
197  }
198 
199  typecheck_expr(code.op0());
200  typecheck_expr(code.op1());
201 
202  implicit_typecast(code.op1(), code.op0().type());
203 }
204 
206 {
207  for(auto &c : code.statements())
208  typecheck_code(c);
209 
210  // do decl-blocks
211 
212  code_blockt new_ops;
213  new_ops.statements().reserve(code.statements().size());
214 
215  for(auto &code_op : code.statements())
216  {
217  if(code_op.is_not_nil())
218  new_ops.add(std::move(code_op));
219  }
220 
221  code.statements().swap(new_ops.statements());
222 }
223 
225 {
226  if(!break_is_allowed)
227  {
229  error() << "break not allowed here" << eom;
230  throw 0;
231  }
232 }
233 
235 {
237  {
239  error() << "continue not allowed here" << eom;
240  throw 0;
241  }
242 }
243 
245 {
246  // this comes with 1 operand, which is a declaration
247  if(code.operands().size()!=1)
248  {
250  error() << "decl expected to have 1 operand" << eom;
251  throw 0;
252  }
253 
254  // op0 must be declaration
255  if(code.op0().id()!=ID_declaration)
256  {
258  error() << "decl statement expected to have declaration as operand"
259  << eom;
260  throw 0;
261  }
262 
263  ansi_c_declarationt declaration;
264  declaration.swap(code.op0());
265 
266  if(declaration.get_is_static_assert())
267  {
268  codet new_code(ID_static_assert);
269  new_code.add_source_location()=code.source_location();
270  new_code.operands().swap(declaration.operands());
271  code.swap(new_code);
272  typecheck_code(code);
273  return; // done
274  }
275 
276  typecheck_declaration(declaration);
277 
278  std::list<codet> new_code;
279 
280  // iterate over declarators
281 
282  for(const auto &d : declaration.declarators())
283  {
284  irep_idt identifier = d.get_name();
285 
286  // look it up
287  symbol_table_baset::symbolst::const_iterator s_it =
288  symbol_table.symbols.find(identifier);
289 
290  if(s_it==symbol_table.symbols.end())
291  {
293  error() << "failed to find decl symbol '" << identifier
294  << "' in symbol table" << eom;
295  throw 0;
296  }
297 
298  const symbolt &symbol=s_it->second;
299 
300  // This must not be an incomplete type, unless it's 'extern'
301  // or a typedef.
302  if(!symbol.is_type &&
303  !symbol.is_extern &&
304  !is_complete_type(symbol.type))
305  {
306  error().source_location=symbol.location;
307  error() << "incomplete type not permitted here" << eom;
308  throw 0;
309  }
310 
311  // see if it's a typedef
312  // or a function
313  // or static
314  if(symbol.is_type || symbol.type.id() == ID_code)
315  {
316  // we ignore
317  }
318  else if(symbol.is_static_lifetime)
319  {
320  // make sure the initialization value is a compile-time constant
321  if(symbol.value.is_not_nil())
322  {
323  exprt init_value = symbol.value;
324  make_constant(init_value);
325  }
326  }
327  else
328  {
329  code_frontend_declt decl(symbol.symbol_expr());
330  decl.add_source_location() = symbol.location;
331  decl.symbol().add_source_location() = symbol.location;
332 
333  // add initializer, if any
334  if(symbol.value.is_not_nil())
335  {
336  decl.operands().resize(2);
337  decl.op1() = symbol.value;
338  }
339 
340  new_code.push_back(decl);
341  }
342  }
343 
344  // stash away any side-effects in the declaration
345  new_code.splice(new_code.begin(), clean_code);
346 
347  if(new_code.empty())
348  {
349  source_locationt source_location=code.source_location();
350  code=code_skipt();
351  code.add_source_location()=source_location;
352  }
353  else if(new_code.size()==1)
354  {
355  code.swap(new_code.front());
356  }
357  else
358  {
359  // build a decl-block
360  auto code_block=code_blockt::from_list(new_code);
361  code_block.set_statement(ID_decl_block);
362  code.swap(code_block);
363  }
364 }
365 
367 {
368  if(type.id() == ID_array)
369  {
370  const auto &array_type = to_array_type(type);
371 
372  if(array_type.size().is_nil())
373  return false;
374 
375  return is_complete_type(array_type.element_type());
376  }
377  else if(type.id()==ID_struct || type.id()==ID_union)
378  {
379  const auto &struct_union_type = to_struct_union_type(type);
380 
381  if(struct_union_type.is_incomplete())
382  return false;
383 
384  for(const auto &c : struct_union_type.components())
385  if(!is_complete_type(c.type()))
386  return false;
387  }
388  else if(type.id()==ID_vector)
389  return is_complete_type(to_vector_type(type).element_type());
390  else if(auto struct_tag_type = type_try_dynamic_cast<struct_tag_typet>(type))
391  {
392  return is_complete_type(follow_tag(*struct_tag_type));
393  }
394  else if(auto union_tag_type = type_try_dynamic_cast<union_tag_typet>(type))
395  {
396  return is_complete_type(follow_tag(*union_tag_type));
397  }
398 
399  return true;
400 }
401 
403 {
404  if(code.operands().size()!=1)
405  {
407  error() << "expression statement expected to have one operand"
408  << eom;
409  throw 0;
410  }
411 
412  exprt &op=code.op0();
413  typecheck_expr(op);
414 }
415 
417 {
418  if(code.operands().size()!=4)
419  {
421  error() << "for expected to have four operands" << eom;
422  throw 0;
423  }
424 
425  // the "for" statement has an implicit block around it,
426  // since code.op0() may contain declarations
427  //
428  // we therefore transform
429  //
430  // for(a;b;c) d;
431  //
432  // to
433  //
434  // { a; for(;b;c) d; }
435  //
436  // if config.ansi_c.for_has_scope
437 
439  code.op0().is_nil())
440  {
441  if(code.op0().is_not_nil())
442  typecheck_code(to_code(code.op0()));
443 
444  if(code.op1().is_nil())
445  code.op1()=true_exprt();
446  else
447  {
448  typecheck_expr(code.op1());
449  implicit_typecast_bool(code.op1());
450  }
451 
452  if(code.op2().is_not_nil())
453  typecheck_expr(code.op2());
454 
455  if(code.op3().is_not_nil())
456  {
457  // save & set flags
458  bool old_break_is_allowed=break_is_allowed;
459  bool old_continue_is_allowed=continue_is_allowed;
460 
462 
463  // recursive call
464  if(to_code(code.op3()).get_statement()==ID_decl_block)
465  {
466  code_blockt code_block;
467  code_block.add_source_location()=code.op3().source_location();
468 
469  code_block.add(std::move(to_code(code.op3())));
470  code.op3().swap(code_block);
471  }
472  typecheck_code(to_code(code.op3()));
473 
474  // restore flags
475  break_is_allowed=old_break_is_allowed;
476  continue_is_allowed=old_continue_is_allowed;
477  }
478  }
479  else
480  {
481  code_blockt code_block;
482  code_block.add_source_location()=code.source_location();
483  if(to_code(code.op3()).get_statement()==ID_block)
484  {
485  code_block.set(
486  ID_C_end_location,
488  }
489  else
490  {
491  code_block.set(
492  ID_C_end_location,
493  code.op3().source_location());
494  }
495 
496  code_block.reserve_operands(2);
497  code_block.add(std::move(to_code(code.op0())));
498  code.op0().make_nil();
499  code_block.add(std::move(code));
500  code.swap(code_block);
501  typecheck_code(code); // recursive call
502  }
503 
506 
507  if(code.find(ID_C_spec_assigns).is_not_nil())
508  {
510  static_cast<unary_exprt &>(code.add(ID_C_spec_assigns)).op().operands());
511  }
512 
513  if(code.find(ID_C_spec_frees).is_not_nil())
514  {
516  static_cast<unary_exprt &>(code.add(ID_C_spec_frees)).op().operands());
517  }
518 }
519 
521 {
522  // record the label
523  if(!labels_defined.emplace(code.get_label(), code.source_location()).second)
524  {
526  error() << "duplicate label '" << code.get_label() << "'" << eom;
527  throw 0;
528  }
529 
530  typecheck_code(code.code());
531 }
532 
534 {
535  if(code.operands().size()!=2)
536  {
538  error() << "switch_case expected to have two operands" << eom;
539  throw 0;
540  }
541 
542  typecheck_code(code.code());
543 
544  if(code.is_default())
545  {
546  if(!case_is_allowed)
547  {
549  error() << "did not expect default label here" << eom;
550  throw 0;
551  }
552  }
553  else
554  {
555  if(!case_is_allowed)
556  {
558  error() << "did not expect `case' here" << eom;
559  throw 0;
560  }
561 
562  exprt &case_expr=code.case_op();
563  typecheck_expr(case_expr);
564  implicit_typecast(case_expr, switch_op_type);
565  make_constant(case_expr);
566  }
567 }
568 
571 {
572  if(!case_is_allowed)
573  {
575  error() << "did not expect `case' here" << eom;
576  throw 0;
577  }
578 
579  typecheck_expr(code.lower());
580  typecheck_expr(code.upper());
583  make_constant(code.lower());
584  make_constant(code.upper());
585  typecheck_code(code.code());
586 }
587 
589 {
590  // these are just declarations, e.g.,
591  // __label__ here, there;
592 }
593 
595 {
596  // we record the label used
598 }
599 
601 {
602  if(code.operands().size()!=1)
603  {
605  error() << "computed-goto expected to have one operand" << eom;
606  throw 0;
607  }
608 
609  exprt &dest=code.op0();
610 
611  if(dest.id()!=ID_dereference)
612  {
614  error() << "computed-goto expected to have dereferencing operand"
615  << eom;
616  throw 0;
617  }
618 
619  typecheck_expr(to_unary_expr(dest).op());
620  dest.type() = void_type();
621 }
622 
624 {
625  if(code.operands().size()!=3)
626  {
628  error() << "ifthenelse expected to have three operands" << eom;
629  throw 0;
630  }
631 
632  exprt &cond=code.cond();
633 
634  typecheck_expr(cond);
635 
637 
638  if(code.then_case().get_statement() == ID_decl_block)
639  {
640  code_blockt code_block({code.then_case()});
641  code_block.add_source_location()=code.then_case().source_location();
642  code.then_case() = code_block;
643  }
644 
645  typecheck_code(code.then_case());
646 
647  if(!code.else_case().is_nil())
648  {
649  if(code.else_case().get_statement() == ID_decl_block)
650  {
651  code_blockt code_block({code.else_case()});
652  code_block.add_source_location()=code.else_case().source_location();
653  code.else_case() = code_block;
654  }
655 
656  typecheck_code(code.else_case());
657  }
658 }
659 
661 {
662  if(code.operands().size()!=1)
663  {
665  error() << "start_thread expected to have one operand" << eom;
666  throw 0;
667  }
668 
669  typecheck_code(to_code(code.op0()));
670 }
671 
673 {
674  if(code.has_return_value())
675  {
677 
678  if(return_type.id() == ID_empty)
679  {
680  // gcc doesn't actually complain, it just warns!
681  if(code.return_value().type().id() != ID_empty)
682  {
684 
685  warning() << "function has return void ";
686  warning() << "but a return statement returning ";
687  warning() << to_string(code.return_value().type());
688  warning() << eom;
689 
691  }
692  }
693  else
695  }
696  else if(
697  return_type.id() != ID_empty && return_type.id() != ID_constructor &&
698  return_type.id() != ID_destructor)
699  {
700  // gcc doesn't actually complain, it just warns!
702  warning() << "non-void function should return a value" << eom;
703 
704  code.return_value() =
706  }
707 }
708 
710 {
711  // we expect a code_switcht, but might return either a code_switcht or a
712  // code_blockt, hence don't use code_switcht in the interface
713  code_switcht &code_switch = to_code_switch(code);
714 
715  typecheck_expr(code_switch.value());
716 
717  // this needs to be promoted
718  implicit_typecast_arithmetic(code_switch.value());
719 
720  // save & set flags
721 
722  bool old_case_is_allowed(case_is_allowed);
723  bool old_break_is_allowed(break_is_allowed);
724  typet old_switch_op_type(switch_op_type);
725 
726  switch_op_type = code_switch.value().type();
728 
729  typecheck_code(code_switch.body());
730 
731  if(code_switch.body().get_statement() == ID_block)
732  {
733  // Collect all declarations before the first case, if there is any case
734  // (including a default one).
735  code_blockt wrapping_block;
736 
737  code_blockt &body_block = to_code_block(code_switch.body());
738  for(auto &statement : body_block.statements())
739  {
740  if(statement.get_statement() == ID_switch_case)
741  break;
742  else if(statement.get_statement() == ID_decl)
743  {
744  if(statement.operands().size() == 1)
745  {
746  wrapping_block.add(code_skipt());
747  wrapping_block.statements().back().swap(statement);
748  }
749  else
750  {
751  PRECONDITION(statement.operands().size() == 2);
752  wrapping_block.add(statement);
753  wrapping_block.statements().back().operands().pop_back();
754  statement.set_statement(ID_assign);
755  }
756  }
757  }
758 
759  if(!wrapping_block.statements().empty())
760  {
761  wrapping_block.add(std::move(code));
762  code.swap(wrapping_block);
763  }
764  }
765 
766  // restore flags
767  case_is_allowed=old_case_is_allowed;
768  break_is_allowed=old_break_is_allowed;
769  switch_op_type=old_switch_op_type;
770 }
771 
773 {
774  if(code.operands().size()!=2)
775  {
777  error() << "while expected to have two operands" << eom;
778  throw 0;
779  }
780 
781  typecheck_expr(code.cond());
783 
784  // save & set flags
785  bool old_break_is_allowed(break_is_allowed);
786  bool old_continue_is_allowed(continue_is_allowed);
787 
789 
790  if(code.body().get_statement()==ID_decl_block)
791  {
792  code_blockt code_block({code.body()});
793  code_block.add_source_location()=code.body().source_location();
794  code.body() = code_block;
795  }
796  typecheck_code(code.body());
797 
798  // restore flags
799  break_is_allowed=old_break_is_allowed;
800  continue_is_allowed=old_continue_is_allowed;
801 
804 
805  if(code.find(ID_C_spec_assigns).is_not_nil())
806  {
808  static_cast<unary_exprt &>(code.add(ID_C_spec_assigns)).op().operands());
809  }
810 
811  if(code.find(ID_C_spec_frees).is_not_nil())
812  {
814  static_cast<unary_exprt &>(code.add(ID_C_spec_frees)).op().operands());
815  }
816 }
817 
819 {
820  if(code.operands().size()!=2)
821  {
823  error() << "do while expected to have two operands" << eom;
824  throw 0;
825  }
826 
827  typecheck_expr(code.cond());
829 
830  // save & set flags
831  bool old_break_is_allowed(break_is_allowed);
832  bool old_continue_is_allowed(continue_is_allowed);
833 
835 
836  if(code.body().get_statement()==ID_decl_block)
837  {
838  code_blockt code_block({code.body()});
839  code_block.add_source_location()=code.body().source_location();
840  code.body() = code_block;
841  }
842  typecheck_code(code.body());
843 
844  // restore flags
845  break_is_allowed=old_break_is_allowed;
846  continue_is_allowed=old_continue_is_allowed;
847 
850 
851  if(code.find(ID_C_spec_assigns).is_not_nil())
852  {
854  static_cast<unary_exprt &>(code.add(ID_C_spec_assigns)).op().operands());
855  }
856 
857  if(code.find(ID_C_spec_frees).is_not_nil())
858  {
860  static_cast<unary_exprt &>(code.add(ID_C_spec_frees)).op().operands());
861  }
862 }
863 
865 {
866  if(has_subexpr(expr, ID_side_effect))
867  {
869  "side-effects not allowed in assigns clause targets",
870  expr.source_location()};
871  }
872  if(has_subexpr(expr, ID_if))
873  {
875  "ternary expressions not allowed in assigns clause targets",
876  expr.source_location()};
877  }
878 }
879 
881 {
882  // compute type
883  typecheck_expr(condition);
884 
885  // make it boolean if needed
886  implicit_typecast_bool(condition);
887 
888  // non-fatal warnings
890  {
891  // Remark: we allow function calls without further checks for now because
892  // they are mandatory for some applications.
893  // The next step must be to check that the called functions have a contract
894  // with an empty assigns clause and that they indeed satisfy their contract
895  // using a CI check.
896  warning().source_location = condition.source_location();
897  warning()
898  << "function with possible side-effect called in target's condition"
899  << eom;
900  }
901 
902  if(condition.type().id() == ID_empty)
903  {
905  "void-typed expressions not allowed as assigns clause conditions",
906  condition.source_location()};
907  }
908 
909  if(has_subexpr(condition, [&](const exprt &subexpr) {
910  return can_cast_expr<side_effect_exprt>(subexpr) &&
912  }))
913  {
915  "side-effects not allowed in assigns clause conditions",
916  condition.source_location()};
917  }
918 
919  if(has_subexpr(condition, ID_if))
920  {
922  "ternary expressions not allowed in assigns clause conditions",
923  condition.source_location()};
924  }
925 }
926 
928  exprt::operandst &targets,
929  const std::function<void(exprt &)> typecheck_target,
930  const std::string &clause_type)
931 {
932  exprt::operandst new_targets;
933 
934  for(auto &target : targets)
935  {
937  {
939  "expected a conditional target group expression in " + clause_type +
940  "clause, found " + id2string(target.id()),
941  target.source_location()};
942  }
943 
944  auto &conditional_target_group = to_conditional_target_group_expr(target);
945  validate_expr(conditional_target_group);
946 
947  // typecheck condition
948  auto &condition = conditional_target_group.condition();
949  typecheck_spec_condition(condition);
950 
951  if(condition.is_true())
952  {
953  // if the condition is trivially true,
954  // simplify expr and expose the bare expressions
955  for(auto &actual_target : conditional_target_group.targets())
956  {
957  typecheck_target(actual_target);
958  new_targets.push_back(actual_target);
959  }
960  }
961  else
962  {
963  // if the condition is not trivially true, typecheck in place
964  for(auto &actual_target : conditional_target_group.targets())
965  {
966  typecheck_target(actual_target);
967  }
968  new_targets.push_back(std::move(target));
969  }
970  }
971 
972  // now each target is either:
973  // - a simple side-effect-free unconditional lvalue expression or
974  // - a conditional target group expression with a non-trivial condition
975 
976  // update original vector in-place
977  std::swap(targets, new_targets);
978 }
979 
981 {
982  const std::function<void(exprt &)> typecheck_target = [&](exprt &target) {
984  };
985  typecheck_conditional_targets(targets, typecheck_target, "assigns");
986 }
987 
989 {
990  const std::function<void(exprt &)> typecheck_target = [&](exprt &target) {
992  };
993  typecheck_conditional_targets(targets, typecheck_target, "frees");
994 }
995 
997 {
998  // compute type
999  typecheck_expr(target);
1000 
1001  if(target.get_bool(ID_C_lvalue))
1002  {
1003  if(target.type().id() == ID_empty)
1004  {
1006  "lvalue expressions with void type not allowed in assigns clauses",
1007  target.source_location()};
1008  }
1009  throw_on_side_effects(target);
1010  return;
1011  }
1013  {
1014  const auto &funcall = to_side_effect_expr_function_call(target);
1015  if(!can_cast_expr<symbol_exprt>(funcall.function()))
1016  {
1018  "function pointer calls not allowed in assigns clauses",
1019  target.source_location());
1020  }
1021 
1022  if(target.type().id() != ID_empty)
1023  {
1025  "expecting void return type for function '" +
1026  id2string(to_symbol_expr(funcall.function()).get_identifier()) +
1027  "' called in assigns clause",
1028  target.source_location());
1029  }
1030 
1031  for(const auto &argument : funcall.arguments())
1032  throw_on_side_effects(argument);
1033  }
1034  else
1035  {
1036  // if we reach this point the target did not pass the checks
1038  "assigns clause target must be a non-void lvalue or a call to a function "
1039  "returning void",
1040  target.source_location());
1041  }
1042 }
1043 
1045 {
1046  // compute type
1047  typecheck_expr(target);
1048  const auto &type = target.type();
1049 
1051  {
1052  // an expression with pointer-type without side effects
1053  throw_on_side_effects(target);
1054  }
1056  {
1057  // A call to a void function symbol without other side effects
1058  const auto &funcall = to_side_effect_expr_function_call(target);
1059 
1060  if(!can_cast_expr<symbol_exprt>(funcall.function()))
1061  {
1063  "function pointer calls not allowed in frees clauses",
1064  target.source_location());
1065  }
1066 
1067  if(type.id() != ID_empty)
1068  {
1070  "expecting void return type for function '" +
1071  id2string(to_symbol_expr(funcall.function()).get_identifier()) +
1072  "' called in frees clause",
1073  target.source_location());
1074  }
1075 
1076  for(const auto &argument : funcall.arguments())
1077  throw_on_side_effects(argument);
1078  }
1079  else
1080  {
1081  // anything else is rejected
1083  "frees clause target must be a pointer-typed expression or a call to a "
1084  "function returning void",
1085  target.source_location());
1086  }
1087 }
1088 
1090 {
1091  if(code.find(ID_C_spec_loop_invariant).is_not_nil())
1092  {
1093  for(auto &invariant :
1094  (static_cast<exprt &>(code.add(ID_C_spec_loop_invariant)).operands()))
1095  {
1096  typecheck_expr(invariant);
1097  implicit_typecast_bool(invariant);
1099  invariant,
1100  ID_old,
1101  CPROVER_PREFIX "old is not allowed in loop invariants.");
1102  }
1103  }
1104 }
1105 
1107 {
1108  if(code.find(ID_C_spec_decreases).is_not_nil())
1109  {
1110  for(auto &decreases_clause_component :
1111  (static_cast<exprt &>(code.add(ID_C_spec_decreases)).operands()))
1112  {
1113  typecheck_expr(decreases_clause_component);
1114  implicit_typecast_arithmetic(decreases_clause_component);
1115  }
1116  }
1117 }
ANSI-CC Language Type Checking.
configt config
Definition: config.cpp:25
API to expression classes that are internal to the C frontend.
const conditional_target_group_exprt & to_conditional_target_group_expr(const exprt &expr)
Cast an exprt to a conditional_target_group_exprt.
Definition: c_expr.h:306
bool can_cast_expr< conditional_target_group_exprt >(const exprt &base)
Definition: c_expr.h:294
void validate_expr(const shuffle_vector_exprt &value)
Definition: c_expr.h:82
ANSI-C Language Type Checking.
empty_typet void_type()
Definition: c_types.cpp:245
const declaratorst & declarators() const
bool get_is_static_assert() const
symbol_table_baset & symbol_table
virtual void implicit_typecast(exprt &expr, const typet &type)
virtual void typecheck_break(codet &code)
std::map< irep_idt, source_locationt > labels_used
virtual void typecheck_expr(exprt &expr)
virtual void typecheck_block(code_blockt &code)
virtual void typecheck_code(codet &code)
virtual void typecheck_while(code_whilet &code)
void disallow_subexpr_by_id(const exprt &, const irep_idt &, const std::string &) const
virtual void throw_on_side_effects(const exprt &expr)
virtual void typecheck_decl(codet &code)
virtual void typecheck_spec_decreases(codet &code)
virtual void make_constant(exprt &expr)
virtual void typecheck_assign(codet &expr)
virtual void typecheck_continue(codet &code)
virtual void implicit_typecast_arithmetic(exprt &expr)
virtual void typecheck_spec_frees_target(exprt &target)
std::list< codet > clean_code
virtual std::string to_string(const exprt &expr)
void typecheck_declaration(ansi_c_declarationt &)
virtual void typecheck_spec_assigns_target(exprt &target)
virtual void typecheck_gcc_local_label(codet &code)
virtual void typecheck_spec_condition(exprt &condition)
virtual void start_typecheck_code()
virtual void typecheck_asm(code_asmt &code)
virtual void typecheck_gcc_computed_goto(codet &code)
virtual void typecheck_conditional_targets(exprt::operandst &targets, const std::function< void(exprt &)> typecheck_target, const std::string &clause_type)
virtual void typecheck_for(codet &code)
virtual void typecheck_switch(codet &code)
virtual void typecheck_spec_frees(exprt::operandst &targets)
virtual void typecheck_expression(codet &code)
virtual void typecheck_return(code_frontend_returnt &)
virtual void typecheck_spec_assigns(exprt::operandst &targets)
virtual bool is_complete_type(const typet &type) const
virtual void typecheck_start_thread(codet &code)
virtual void typecheck_switch_case(code_switch_caset &code)
virtual void typecheck_spec_loop_invariant(codet &code)
virtual void typecheck_gcc_switch_case_range(code_gcc_switch_case_ranget &)
virtual void implicit_typecast_bool(exprt &expr)
virtual void typecheck_dowhile(code_dowhilet &code)
virtual void typecheck_ifthenelse(code_ifthenelset &code)
virtual void typecheck_goto(code_gotot &code)
virtual void typecheck_label(code_labelt &code)
std::map< irep_idt, source_locationt > labels_defined
codet representation of an inline assembler statement.
Definition: std_code.h:1253
const irep_idt & get_flavor() const
Definition: std_code.h:1263
A codet representing sequential composition of program statements.
Definition: std_code.h:130
static code_blockt from_list(const std::list< codet > &_list)
Definition: std_code.h:148
source_locationt end_location() const
Definition: std_code.h:187
void add(const codet &code)
Definition: std_code.h:168
code_operandst & statements()
Definition: std_code.h:138
codet representation of a do while statement.
Definition: std_code.h:672
const exprt & cond() const
Definition: std_code.h:679
const codet & body() const
Definition: std_code.h:689
A codet representing the declaration of a local variable.
Definition: std_code.h:347
symbol_exprt & symbol()
Definition: std_code.h:354
codet representation of a "return from a function" statement.
Definition: std_code.h:893
const exprt & return_value() const
Definition: std_code.h:903
bool has_return_value() const
Definition: std_code.h:913
codet representation of a switch-case, i.e. a case statement within a switch.
Definition: std_code.h:1097
codet & code()
the statement to be executed when the case applies
Definition: std_code.h:1131
const exprt & lower() const
lower bound of range
Definition: std_code.h:1107
const exprt & upper() const
upper bound of range
Definition: std_code.h:1119
codet representation of a goto statement.
Definition: std_code.h:841
const irep_idt & get_destination() const
Definition: std_code.h:853
codet representation of an if-then-else statement.
Definition: std_code.h:460
const codet & then_case() const
Definition: std_code.h:488
const exprt & cond() const
Definition: std_code.h:478
const codet & else_case() const
Definition: std_code.h:498
codet representation of a label for branch targets.
Definition: std_code.h:959
const irep_idt & get_label() const
Definition: std_code.h:967
codet & code()
Definition: std_code.h:977
A codet representing a skip statement.
Definition: std_code.h:322
codet representation of a switch-case, i.e. a case statement within a switch.
Definition: std_code.h:1023
codet & code()
Definition: std_code.h:1050
const exprt & case_op() const
Definition: std_code.h:1040
bool is_default() const
Definition: std_code.h:1030
codet representing a switch statement.
Definition: std_code.h:548
const exprt & value() const
Definition: std_code.h:555
const codet & body() const
Definition: std_code.h:565
codet representing a while statement.
Definition: std_code.h:610
const exprt & cond() const
Definition: std_code.h:617
const codet & body() const
Definition: std_code.h:627
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:29
exprt & op3()
Definition: expr.h:142
exprt & op1()
Definition: expr.h:136
exprt & op2()
Definition: expr.h:139
exprt & op0()
Definition: expr.h:133
const irep_idt & get_statement() const
Definition: std_code_base.h:65
struct configt::ansi_ct ansi_c
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
The empty type.
Definition: std_types.h:51
Base class for all expressions.
Definition: expr.h:56
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition: expr.cpp:147
std::vector< exprt > operandst
Definition: expr.h:58
source_locationt & add_source_location()
Definition: expr.h:236
const source_locationt & source_location() const
Definition: expr.h:231
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:34
void reserve_operands(operandst::size_type n)
Definition: expr.h:158
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
Thrown when we can't handle something in an input source file.
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:412
bool is_not_nil() const
Definition: irep.h:372
const irep_idt & id() const
Definition: irep.h:388
void make_nil()
Definition: irep.h:446
void swap(irept &irep)
Definition: irep.h:434
irept & add(const irep_idt &name)
Definition: irep.cpp:103
bool is_nil() const
Definition: irep.h:368
source_locationt source_location
Definition: message.h:239
mstreamt & error() const
Definition: message.h:391
mstreamt & warning() const
Definition: message.h:396
static eomt eom
Definition: message.h:289
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A side_effect_exprt that returns a non-deterministically chosen value.
Definition: std_code.h:1520
void value(const irep_idt &)
const irep_idt & get_identifier() const
Definition: std_expr.h:160
const symbolst & symbols
Read-only field, used to look up symbols given their names.
Symbol table entry.
Definition: symbol.h:28
bool is_extern
Definition: symbol.h:74
bool is_static_lifetime
Definition: symbol.h:70
bool is_type
Definition: symbol.h:61
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
typet type
Type of symbol.
Definition: symbol.h:31
exprt value
Initial value of symbol.
Definition: symbol.h:34
The Boolean constant true.
Definition: std_expr.h:3068
Semantic type conversion.
Definition: std_expr.h:2073
The type of an expression, extends irept.
Definition: type.h:29
Generic base class for unary expressions.
Definition: std_expr.h:361
const exprt & op() const
Definition: std_expr.h:391
#define CPROVER_PREFIX
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
Definition: expr_util.cpp:115
Deprecated expression utility functions.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
Definition: pointer_expr.h:80
Ranges: pair of begin and end iterators, which can be initialized from containers,...
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
const code_ifthenelset & to_code_ifthenelse(const codet &code)
Definition: std_code.h:530
const code_gotot & to_code_goto(const codet &code)
Definition: std_code.h:875
const code_whilet & to_code_while(const codet &code)
Definition: std_code.h:654
const code_switch_caset & to_code_switch_case(const codet &code)
Definition: std_code.h:1077
const code_labelt & to_code_label(const codet &code)
Definition: std_code.h:1004
side_effect_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
Definition: std_code.h:1739
const code_dowhilet & to_code_dowhile(const codet &code)
Definition: std_code.h:716
const code_switcht & to_code_switch(const codet &code)
Definition: std_code.h:592
bool can_cast_expr< side_effect_expr_function_callt >(const exprt &base)
Definition: std_code.h:1730
const code_blockt & to_code_block(const codet &code)
Definition: std_code.h:203
const code_frontend_returnt & to_code_frontend_return(const codet &code)
Definition: std_code.h:943
bool can_cast_expr< side_effect_exprt >(const exprt &base)
Definition: std_code.h:1498
const code_gcc_switch_case_ranget & to_code_gcc_switch_case_range(const codet &code)
Definition: std_code.h:1161
code_asm_gcct & to_code_asm_gcc(codet &code)
Definition: std_code.h:1373
code_asmt & to_code_asm(codet &code)
Definition: std_code.h:1282
const codet & to_code(const exprt &expr)
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
bool can_cast_expr< symbol_exprt >(const exprt &base)
Definition: std_expr.h:256
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:426
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1113
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
const string_constantt & to_string_constant(const exprt &expr)
bool for_has_scope
Definition: config.h:151
A range is a pair of a begin and an end iterators.
Definition: range.h:396
Author: Diffblue Ltd.