CBMC
c_typecheck_base.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: ANSI-C Conversion / Type Checking
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "c_typecheck_base.h"
13 
14 #include <util/c_types.h>
15 #include <util/config.h>
16 #include <util/expr_util.h>
17 #include <util/mathematical_expr.h>
18 #include <util/std_types.h>
19 
20 #include "ansi_c_declaration.h"
21 #include "c_storage_spec.h"
22 #include "expr2c.h"
23 
24 std::string c_typecheck_baset::to_string(const exprt &expr)
25 {
26  return expr2c(expr, *this);
27 }
28 
29 std::string c_typecheck_baset::to_string(const typet &type)
30 {
31  return type2c(type, *this);
32 }
33 
34 void c_typecheck_baset::move_symbol(symbolt &symbol, symbolt *&new_symbol)
35 {
36  symbol.mode=mode;
37  symbol.module=module;
38 
39  if(symbol_table.move(symbol, new_symbol))
40  {
42  error() << "failed to move symbol '" << symbol.name << "' into symbol table"
43  << eom;
44  throw 0;
45  }
46 }
47 
49 {
50  bool is_function=symbol.type.id()==ID_code;
51 
52  const typet &final_type=follow(symbol.type);
53 
54  // set a few flags
55  symbol.is_lvalue=!symbol.is_type && !symbol.is_macro;
56 
57  irep_idt root_name=symbol.base_name;
58  irep_idt new_name=symbol.name;
59 
60  if(symbol.is_file_local)
61  {
62  // file-local stuff -- stays as is
63  // collisions are resolved during linking
64  }
65  else if(symbol.is_extern && !is_function)
66  {
67  // variables marked as "extern" go into the global namespace
68  // and have static lifetime
69  new_name=root_name;
70  symbol.is_static_lifetime=true;
71 
72  if(symbol.value.is_not_nil())
73  {
74  // According to the C standard this should be an error, but at least some
75  // versions of Visual Studio insist to use this in their C library, and
76  // GCC just warns as well.
78  warning() << "`extern' symbol should not have an initializer" << eom;
79  }
80  }
81  else if(!is_function && symbol.value.id()==ID_code)
82  {
84  error() << "only functions can have a function body" << eom;
85  throw 0;
86  }
87 
88  // set the pretty name
89  if(symbol.is_type && final_type.id() == ID_struct)
90  {
91  symbol.pretty_name="struct "+id2string(symbol.base_name);
92  }
93  else if(symbol.is_type && final_type.id() == ID_union)
94  {
95  symbol.pretty_name="union "+id2string(symbol.base_name);
96  }
97  else if(symbol.is_type && final_type.id() == ID_c_enum)
98  {
99  symbol.pretty_name="enum "+id2string(symbol.base_name);
100  }
101  else
102  {
103  symbol.pretty_name=new_name;
104  }
105 
106  if(!symbol.is_type && !symbol.is_extern && symbol.type.id() == ID_empty)
107  {
108  error().source_location = symbol.location;
109  error() << "void-typed symbol not permitted" << eom;
110  throw 0;
111  }
112 
113  // see if we have it already
114  symbol_tablet::symbolst::const_iterator old_it=
115  symbol_table.symbols.find(symbol.name);
116 
117  if(old_it==symbol_table.symbols.end())
118  {
119  // just put into symbol_table
120  symbolt *new_symbol;
121  move_symbol(symbol, new_symbol);
122 
123  typecheck_new_symbol(*new_symbol);
124  }
125  else
126  {
127  if(old_it->second.is_type!=symbol.is_type)
128  {
129  error().source_location=symbol.location;
130  error() << "redeclaration of '" << symbol.display_name()
131  << "' as a different kind of symbol" << eom;
132  throw 0;
133  }
134 
135  symbolt &existing_symbol = symbol_table.get_writeable_ref(symbol.name);
136  if(symbol.is_type)
137  typecheck_redefinition_type(existing_symbol, symbol);
138  else
139  typecheck_redefinition_non_type(existing_symbol, symbol);
140  }
141 }
142 
144 {
145  if(symbol.is_parameter)
147 
148  // check initializer, if needed
149 
150  if(symbol.type.id()==ID_code)
151  {
152  if(symbol.value.is_not_nil() &&
153  !symbol.is_macro)
154  {
155  typecheck_function_body(symbol);
156  }
157  else if(
158  symbol.is_macro ||
160  {
161  // we don't need the identifiers
162  for(auto &parameter : to_code_type(symbol.type).parameters())
163  parameter.set_identifier(irep_idt());
164  }
165  }
166  else if(!symbol.is_macro)
167  {
168  // check the initializer
169  do_initializer(symbol);
170  }
171 }
172 
174  symbolt &old_symbol,
175  symbolt &new_symbol)
176 {
177  const typet &final_old=follow(old_symbol.type);
178  const typet &final_new=follow(new_symbol.type);
179 
180  // see if we had something incomplete before
181  if(
182  (final_old.id() == ID_struct &&
183  to_struct_type(final_old).is_incomplete()) ||
184  (final_old.id() == ID_union && to_union_type(final_old).is_incomplete()) ||
185  (final_old.id() == ID_c_enum && to_c_enum_type(final_old).is_incomplete()))
186  {
187  // is the new one complete?
188  if(
189  final_new.id() == final_old.id() &&
190  ((final_new.id() == ID_struct &&
191  !to_struct_type(final_new).is_incomplete()) ||
192  (final_new.id() == ID_union &&
193  !to_union_type(final_new).is_incomplete()) ||
194  (final_new.id() == ID_c_enum &&
195  !to_c_enum_type(final_new).is_incomplete())))
196  {
197  // overwrite location
198  old_symbol.location=new_symbol.location;
199 
200  // move body
201  old_symbol.type.swap(new_symbol.type);
202  }
203  else if(new_symbol.type.id()==old_symbol.type.id())
204  return; // ignore
205  else
206  {
207  error().source_location=new_symbol.location;
208  error() << "conflicting definition of type symbol '"
209  << new_symbol.display_name() << '\'' << eom;
210  throw 0;
211  }
212  }
213  else
214  {
215  // see if new one is just a tag
216  if(
217  (final_new.id() == ID_struct &&
218  to_struct_type(final_new).is_incomplete()) ||
219  (final_new.id() == ID_union &&
220  to_union_type(final_new).is_incomplete()) ||
221  (final_new.id() == ID_c_enum &&
222  to_c_enum_type(final_new).is_incomplete()))
223  {
224  if(final_old.id() == final_new.id())
225  {
226  // just ignore silently
227  }
228  else
229  {
230  // arg! new tag type
231  error().source_location=new_symbol.location;
232  error() << "conflicting definition of tag symbol '"
233  << new_symbol.display_name() << '\'' << eom;
234  throw 0;
235  }
236  }
238  final_new.id()==ID_c_enum && final_old.id()==ID_c_enum)
239  {
240  // under Windows, ignore this silently;
241  // MSC doesn't think this is a problem, but GCC complains.
242  }
243  else if(
245  final_new.id() == ID_pointer && final_old.id() == ID_pointer &&
246  follow(to_pointer_type(final_new).base_type()).id() == ID_c_enum &&
247  follow(to_pointer_type(final_old).base_type()).id() == ID_c_enum)
248  {
249  // under Windows, ignore this silently;
250  // MSC doesn't think this is a problem, but GCC complains.
251  }
252  else
253  {
254  // see if it changed
255  if(follow(new_symbol.type)!=follow(old_symbol.type))
256  {
257  error().source_location=new_symbol.location;
258  error() << "type symbol '" << new_symbol.display_name()
259  << "' defined twice:\n"
260  << "Original: " << to_string(old_symbol.type) << "\n"
261  << " New: " << to_string(new_symbol.type) << eom;
262  throw 0;
263  }
264  }
265  }
266 }
267 
269  const struct_typet &old_type,
270  const struct_typet &new_type)
271 {
272  const struct_typet::componentst &old_components = old_type.components();
273  const struct_typet::componentst &new_components = new_type.components();
274 
275  if(old_components.size() != new_components.size())
276  return false;
277 
278  if(old_components.empty())
279  return false;
280 
281  for(std::size_t i = 0; i < old_components.size() - 1; ++i)
282  {
283  if(old_components[i].type() != new_components[i].type())
284  return false;
285  }
286 
287  if(
288  old_components.back().type().id() != ID_array ||
289  new_components.back().type().id() != ID_array)
290  {
291  return false;
292  }
293 
294  const auto &old_array_type = to_array_type(old_components.back().type());
295  const auto &new_array_type = to_array_type(new_components.back().type());
296 
297  return old_array_type.element_type() == new_array_type.element_type() &&
298  old_array_type.get_bool(ID_C_flexible_array_member) &&
299  new_array_type.get_bool(ID_C_flexible_array_member) &&
300  (old_array_type.size().is_nil() || old_array_type.size().is_zero());
301 }
302 
304  symbolt &old_symbol,
305  symbolt &new_symbol)
306 {
307  const typet &final_old=follow(old_symbol.type);
308  const typet &initial_new=follow(new_symbol.type);
309 
310  if(
311  final_old.id() == ID_array &&
312  to_array_type(final_old).size().is_not_nil() &&
313  initial_new.id() == ID_array &&
314  to_array_type(initial_new).size().is_nil() &&
315  to_array_type(final_old).element_type() ==
316  to_array_type(initial_new).element_type())
317  {
318  // this is ok, just use old type
319  new_symbol.type=old_symbol.type;
320  }
321  else if(
322  final_old.id() == ID_array && to_array_type(final_old).size().is_nil() &&
323  initial_new.id() == ID_array &&
324  to_array_type(initial_new).size().is_not_nil() &&
325  to_array_type(final_old).element_type() ==
326  to_array_type(initial_new).element_type())
327  {
328  // update the type to enable the use of sizeof(x) on the
329  // right-hand side of a definition of x
330  old_symbol.type=new_symbol.type;
331  }
332 
333  // do initializer, this may change the type
334  if(new_symbol.type.id() != ID_code && !new_symbol.is_macro)
335  do_initializer(new_symbol);
336 
337  const typet &final_new=follow(new_symbol.type);
338 
339  // K&R stuff?
340  if(old_symbol.type.id()==ID_KnR)
341  {
342  // check the type
343  if(final_new.id()==ID_code)
344  {
345  error().source_location=new_symbol.location;
346  error() << "function type not allowed for K&R function parameter"
347  << eom;
348  throw 0;
349  }
350 
351  // fix up old symbol -- we now got the type
352  old_symbol.type=new_symbol.type;
353  return;
354  }
355 
356  if(final_new.id()==ID_code)
357  {
358  if(final_old.id()!=ID_code)
359  {
360  error().source_location=new_symbol.location;
361  error() << "error: function symbol '" << new_symbol.display_name()
362  << "' redefined with a different type:\n"
363  << "Original: " << to_string(old_symbol.type) << "\n"
364  << " New: " << to_string(new_symbol.type) << eom;
365  throw 0;
366  }
367 
368  code_typet &old_ct=to_code_type(old_symbol.type);
369  code_typet &new_ct=to_code_type(new_symbol.type);
370 
371  const bool inlined = old_ct.get_inlined() || new_ct.get_inlined();
372 
373  if(old_ct.has_ellipsis() && !new_ct.has_ellipsis())
374  old_ct=new_ct;
375  else if(!old_ct.has_ellipsis() && new_ct.has_ellipsis())
376  {
377  if(to_code_with_contract_type(new_ct).has_contract())
378  {
379  error().source_location = new_symbol.location;
380  error() << "code contract on incomplete function re-declaration" << eom;
381  throw 0;
382  }
383  new_ct=old_ct;
384  }
385 
386  if(inlined)
387  {
388  old_ct.set_inlined(true);
389  new_ct.set_inlined(true);
390  }
391 
392  // do body
393 
394  if(new_symbol.value.is_not_nil())
395  {
396  if(old_symbol.value.is_not_nil())
397  {
398  // gcc allows re-definition if the first
399  // definition is marked as "extern inline"
400 
401  if(
402  old_ct.get_inlined() &&
407  {
408  // overwrite "extern inline" properties
409  old_symbol.is_extern=new_symbol.is_extern;
410  old_symbol.is_file_local=new_symbol.is_file_local;
411 
412  // remove parameter declarations to avoid conflicts
413  for(const auto &old_parameter : old_ct.parameters())
414  {
415  const irep_idt &identifier = old_parameter.get_identifier();
416 
417  symbol_tablet::symbolst::const_iterator p_s_it=
418  symbol_table.symbols.find(identifier);
419  if(p_s_it!=symbol_table.symbols.end())
420  symbol_table.erase(p_s_it);
421  }
422  }
423  else
424  {
425  error().source_location=new_symbol.location;
426  error() << "function body '" << new_symbol.display_name()
427  << "' defined twice" << eom;
428  throw 0;
429  }
430  }
431  else if(inlined)
432  {
433  // preserve "extern inline" properties
434  old_symbol.is_extern=new_symbol.is_extern;
435  old_symbol.is_file_local=new_symbol.is_file_local;
436  }
437  else if(new_symbol.is_weak)
438  {
439  // weak symbols
440  old_symbol.is_weak=true;
441  }
442 
443  if(new_symbol.is_macro)
444  old_symbol.is_macro=true;
445  else
446  typecheck_function_body(new_symbol);
447 
448  // overwrite location
449  old_symbol.location=new_symbol.location;
450 
451  // move body
452  old_symbol.value.swap(new_symbol.value);
453 
454  // overwrite type (because of parameter names)
455  old_symbol.type=new_symbol.type;
456  }
457  else if(to_code_with_contract_type(new_ct).has_contract())
458  {
459  // overwrite type to add contract, but keep the old parameter identifiers
460  // (if any)
461  auto new_parameters_it = new_ct.parameters().begin();
462  for(auto &p : old_ct.parameters())
463  {
464  if(new_parameters_it != new_ct.parameters().end())
465  {
466  new_parameters_it->set_identifier(p.get_identifier());
467  ++new_parameters_it;
468  }
469  }
470 
471  old_symbol.type = new_symbol.type;
472  }
473 
474  return;
475  }
476 
477  if(final_old!=final_new)
478  {
479  if(
480  final_old.id() == ID_array && to_array_type(final_old).size().is_nil() &&
481  final_new.id() == ID_array &&
482  to_array_type(final_new).size().is_not_nil() &&
483  to_array_type(final_old).element_type() ==
484  to_array_type(final_new).element_type())
485  {
486  old_symbol.type=new_symbol.type;
487  }
488  else if(
489  final_old.id() == ID_pointer &&
490  to_pointer_type(final_old).base_type().id() == ID_code &&
491  to_code_type(to_pointer_type(final_old).base_type()).has_ellipsis() &&
492  final_new.id() == ID_pointer &&
493  to_pointer_type(final_new).base_type().id() == ID_code)
494  {
495  // to allow
496  // int (*f) ();
497  // int (*f) (int)=0;
498  old_symbol.type=new_symbol.type;
499  }
500  else if(
501  final_old.id() == ID_pointer &&
502  to_pointer_type(final_old).base_type().id() == ID_code &&
503  final_new.id() == ID_pointer &&
504  to_pointer_type(final_new).base_type().id() == ID_code &&
505  to_code_type(to_pointer_type(final_new).base_type()).has_ellipsis())
506  {
507  // to allow
508  // int (*f) (int)=0;
509  // int (*f) ();
510  }
511  else if(
512  final_old.id() == ID_struct && final_new.id() == ID_struct &&
514  to_struct_type(final_old), to_struct_type(final_new)))
515  {
516  old_symbol.type = new_symbol.type;
517  }
518  else
519  {
520  error().source_location=new_symbol.location;
521  error() << "symbol '" << new_symbol.display_name()
522  << "' redefined with a different type:\n"
523  << "Original: " << to_string(old_symbol.type) << "\n"
524  << " New: " << to_string(new_symbol.type) << eom;
525  throw 0;
526  }
527  }
528  else // finals are equal
529  {
530  }
531 
532  // do value
533  if(new_symbol.value.is_not_nil())
534  {
535  // see if we already have one
536  if(old_symbol.value.is_not_nil())
537  {
538  if(
539  new_symbol.is_macro && final_new.id() == ID_c_enum &&
540  old_symbol.value.is_constant() && new_symbol.value.is_constant() &&
541  old_symbol.value.get(ID_value) == new_symbol.value.get(ID_value))
542  {
543  // ignore
544  }
545  else
546  {
548  warning() << "symbol '" << new_symbol.display_name()
549  << "' already has an initial value" << eom;
550  }
551  }
552  else
553  {
554  old_symbol.value=new_symbol.value;
555  old_symbol.type=new_symbol.type;
556  old_symbol.is_macro=new_symbol.is_macro;
557  }
558  }
559 
560  // take care of some flags
561  if(old_symbol.is_extern && !new_symbol.is_extern)
562  old_symbol.location=new_symbol.location;
563 
564  old_symbol.is_extern=old_symbol.is_extern && new_symbol.is_extern;
565 
566  // We should likely check is_volatile and
567  // is_thread_local for consistency. GCC complains if these
568  // mismatch.
569 }
570 
572 {
573  if(symbol.value.id() != ID_code)
574  {
575  error().source_location = symbol.location;
576  error() << "function '" << symbol.name << "' is initialized with "
577  << symbol.value.id() << eom;
578  throw 0;
579  }
580 
581  code_typet &code_type = to_code_type(symbol.type);
582 
583  // reset labels
584  labels_used.clear();
585  labels_defined.clear();
586 
587  // fix type
588  symbol.value.type()=code_type;
589 
590  // set return type
591  return_type=code_type.return_type();
592 
593  // Add the parameter declarations into the symbol table
595 
596  // typecheck the body code
597  typecheck_code(to_code(symbol.value));
598 
599  // check the labels
600  for(const auto &label : labels_used)
601  {
602  if(labels_defined.find(label.first) == labels_defined.end())
603  {
604  error().source_location = label.second;
605  error() << "branching label '" << label.first
606  << "' is not defined in function" << eom;
607  throw 0;
608  }
609  }
610 }
611 
613  const irep_idt &asm_label,
614  symbolt &symbol)
615 {
616  const irep_idt orig_name=symbol.name;
617 
618  // restrict renaming to functions and global variables;
619  // procedure-local ones would require fixing the scope, as we
620  // do for parameters below
621  if(!asm_label.empty() &&
622  !symbol.is_type &&
623  (symbol.type.id()==ID_code || symbol.is_static_lifetime))
624  {
625  symbol.name=asm_label;
626  symbol.base_name=asm_label;
627  }
628 
629  if(symbol.name!=orig_name)
630  {
631  if(!asm_label_map.insert(
632  std::make_pair(orig_name, asm_label)).second)
633  {
634  if(asm_label_map[orig_name]!=asm_label)
635  {
636  error().source_location=symbol.location;
637  error() << "error: replacing asm renaming "
638  << asm_label_map[orig_name] << " by "
639  << asm_label << eom;
640  throw 0;
641  }
642  }
643  }
644  else if(asm_label.empty())
645  {
646  asm_label_mapt::const_iterator entry=
647  asm_label_map.find(symbol.name);
648  if(entry!=asm_label_map.end())
649  {
650  symbol.name=entry->second;
651  symbol.base_name=entry->second;
652  }
653  }
654 
655  if(symbol.name!=orig_name &&
656  symbol.type.id()==ID_code &&
657  symbol.value.is_not_nil() && !symbol.is_macro)
658  {
659  const code_typet &code_type=to_code_type(symbol.type);
660 
661  for(const auto &p : code_type.parameters())
662  {
663  const irep_idt &p_bn = p.get_base_name();
664  if(p_bn.empty())
665  continue;
666 
667  irep_idt p_id=id2string(orig_name)+"::"+id2string(p_bn);
668  irep_idt p_new_id=id2string(symbol.name)+"::"+id2string(p_bn);
669 
670  if(!asm_label_map.insert(
671  std::make_pair(p_id, p_new_id)).second)
672  assert(asm_label_map[p_id]==p_new_id);
673  }
674  }
675 }
676 
678  const exprt &expr,
679  std::string &clause_type)
680 {
682  expr, ID_old, CPROVER_PREFIX "old is not allowed in " + clause_type + ".");
684  expr,
685  ID_loop_entry,
686  CPROVER_PREFIX "loop_entry is not allowed in " + clause_type + ".");
687 
688  const irep_idt id = CPROVER_PREFIX "return_value";
689  auto pred = [&](const exprt &expr) {
690  if(!can_cast_expr<symbol_exprt>(expr))
691  return false;
692 
693  return to_symbol_expr(expr).get_identifier() == id;
694  };
695 
696  if(!has_subexpr(expr, pred))
697  return;
698 
700  id2string(id) + " is not allowed in " + id2string(clause_type) + ".",
701  expr.source_location());
702 }
703 
705  ansi_c_declarationt &declaration)
706 {
707  if(declaration.get_is_static_assert())
708  {
709  codet code(ID_static_assert);
710  code.add_source_location() = declaration.source_location();
711  code.operands().swap(declaration.operands());
712  typecheck_code(code);
713  }
714  else
715  {
716  // get storage spec
717  c_storage_spect c_storage_spec(declaration.type());
718 
719  // first typecheck the type of the declaration
720  typecheck_type(declaration.type());
721 
722  // mark as 'already typechecked'
724 
725  // Now do declarators, if any.
726  for(auto &declarator : declaration.declarators())
727  {
728  c_storage_spect full_spec(declaration.full_type(declarator));
729  full_spec|=c_storage_spec;
730 
731  declaration.set_is_inline(full_spec.is_inline);
732  declaration.set_is_static(full_spec.is_static);
733  declaration.set_is_extern(full_spec.is_extern);
734  declaration.set_is_thread_local(full_spec.is_thread_local);
735  declaration.set_is_register(full_spec.is_register);
736  declaration.set_is_typedef(full_spec.is_typedef);
737  declaration.set_is_weak(full_spec.is_weak);
738  declaration.set_is_used(full_spec.is_used);
739 
740  symbolt symbol;
741  declaration.to_symbol(declarator, symbol);
742  current_symbol=symbol;
743 
744  // now check other half of type
745  typecheck_type(symbol.type);
746 
747  if(!full_spec.alias.empty())
748  {
749  if(symbol.value.is_not_nil())
750  {
751  error().source_location=symbol.location;
752  error() << "alias attribute cannot be used with a body"
753  << eom;
754  throw 0;
755  }
756 
757  // alias function need not have been declared yet, thus
758  // can't lookup
759  // also cater for renaming/placement in sections
760  const auto &renaming_entry = asm_label_map.find(full_spec.alias);
761  if(renaming_entry == asm_label_map.end())
762  symbol.value = symbol_exprt::typeless(full_spec.alias);
763  else
764  symbol.value = symbol_exprt::typeless(renaming_entry->second);
765  symbol.is_macro=true;
766  }
767 
768  if(full_spec.section.empty())
769  apply_asm_label(full_spec.asm_label, symbol);
770  else
771  {
772  // section name is not empty, do a bit of parsing
773  std::string asm_name = id2string(full_spec.section);
774 
775  if(asm_name[0] == '.')
776  {
777  std::string::size_type primary_section = asm_name.find('.', 1);
778 
779  if(primary_section != std::string::npos)
780  asm_name.resize(primary_section);
781  }
782 
783  asm_name += "$$";
784 
785  if(!full_spec.asm_label.empty())
786  asm_name+=id2string(full_spec.asm_label);
787  else
788  asm_name+=id2string(symbol.name);
789 
790  apply_asm_label(asm_name, symbol);
791  }
792 
793  irep_idt identifier=symbol.name;
794  declarator.set_name(identifier);
795 
796  typecheck_symbol(symbol);
797 
798  // check the contract, if any
799  symbolt &new_symbol = symbol_table.get_writeable_ref(identifier);
800  if(
801  new_symbol.type.id() == ID_code &&
803  {
804  code_with_contract_typet code_type =
805  to_code_with_contract_type(new_symbol.type);
806 
807  // ensure parameter declarations are available for type checking to
808  // succeed
809  binding_exprt::variablest temporary_parameter_symbols;
810 
811  const auto &return_type = code_type.return_type();
812  if(return_type.id() != ID_empty)
813  {
814  parameter_map[CPROVER_PREFIX "return_value"] = return_type;
815  temporary_parameter_symbols.emplace_back(
816  CPROVER_PREFIX "return_value", return_type);
817  }
818 
819  std::size_t anon_counter = 0;
820  for(auto &p : code_type.parameters())
821  {
822  // may be anonymous
823  if(p.get_base_name().empty())
824  p.set_base_name("#anon" + std::to_string(anon_counter++));
825 
826  // produce identifier
827  const irep_idt &base_name = p.get_base_name();
828  irep_idt parameter_identifier =
829  id2string(identifier) + "::" + id2string(base_name);
830 
831  p.set_identifier(parameter_identifier);
832 
833  PRECONDITION(
834  parameter_map.find(parameter_identifier) == parameter_map.end());
835  parameter_map[parameter_identifier] = p.type();
836  temporary_parameter_symbols.emplace_back(
837  parameter_identifier, p.type());
838  }
839 
840  for(auto &expr : code_type.requires_contract())
841  {
843  std::string clause_type = "function pointer preconditions";
844  check_history_expr_return_value(expr, clause_type);
845  lambda_exprt lambda{temporary_parameter_symbols, expr};
846  lambda.add_source_location() = expr.source_location();
847  expr.swap(lambda);
848  }
849 
850  for(auto &requires : code_type.requires())
851  {
852  typecheck_expr(requires);
853  implicit_typecast_bool(requires);
854  std::string clause_type = "preconditions";
855  check_history_expr_return_value(requires, clause_type);
856  lambda_exprt lambda{temporary_parameter_symbols, requires};
857  lambda.add_source_location() = requires.source_location();
858  requires.swap(lambda);
859  }
860 
861  typecheck_spec_assigns(code_type.assigns());
862  for(auto &assigns : code_type.assigns())
863  {
864  std::string clause_type = "assigns clauses";
865  check_history_expr_return_value(assigns, clause_type);
866  lambda_exprt lambda{temporary_parameter_symbols, assigns};
867  lambda.add_source_location() = assigns.source_location();
868  assigns.swap(lambda);
869  }
870 
871  for(auto &expr : code_type.ensures_contract())
872  {
875  expr,
876  ID_loop_entry,
877  CPROVER_PREFIX "loop_entry is not allowed in postconditions.");
878  lambda_exprt lambda{temporary_parameter_symbols, expr};
879  lambda.add_source_location() = expr.source_location();
880  expr.swap(lambda);
881  }
882 
883  for(auto &ensures : code_type.ensures())
884  {
885  typecheck_expr(ensures);
886  implicit_typecast_bool(ensures);
888  ensures,
889  ID_loop_entry,
890  CPROVER_PREFIX "loop_entry is not allowed in postconditions.");
891  lambda_exprt lambda{temporary_parameter_symbols, ensures};
892  lambda.add_source_location() = ensures.source_location();
893  ensures.swap(lambda);
894  }
895 
896  for(const auto &parameter_sym : temporary_parameter_symbols)
897  parameter_map.erase(parameter_sym.get_identifier());
898 
899  // create a contract symbol
900  symbolt contract;
901  contract.name = "contract::" + id2string(new_symbol.name);
902  contract.base_name = new_symbol.base_name;
903  contract.pretty_name = new_symbol.pretty_name;
904  contract.is_property = true;
905  contract.type = code_type;
906  contract.mode = new_symbol.mode;
907  contract.module = module;
908  contract.location = new_symbol.location;
909 
910  auto entry = symbol_table.insert(std::move(contract));
911  if(!entry.second)
912  {
913  error().source_location = new_symbol.location;
914  error() << "contract '" << new_symbol.display_name()
915  << "' already set at " << entry.first.location.as_string()
916  << eom;
917  throw 0;
918  }
919 
920  // Remove the contract from the original symbol as we have created a
921  // dedicated contract symbol.
922  new_symbol.type.remove(ID_C_spec_assigns);
923  new_symbol.type.remove(ID_C_spec_ensures);
924  new_symbol.type.remove(ID_C_spec_ensures_contract);
925  new_symbol.type.remove(ID_C_spec_requires);
926  new_symbol.type.remove(ID_C_spec_requires_contract);
927  }
928  }
929  }
930 }
931 
933 {
935 
936  code_typet &code_type = to_code_type(symbol.type);
937 
938  unsigned anon_counter = 0;
939 
940  // Add the parameter declarations into the symbol table.
941  for(auto &p : code_type.parameters())
942  {
943  // may be anonymous
944  if(p.get_base_name().empty())
945  {
946  irep_idt base_name = "#anon" + std::to_string(anon_counter++);
947  p.set_base_name(base_name);
948  }
949 
950  // produce identifier
951  irep_idt base_name = p.get_base_name();
952  irep_idt identifier = id2string(symbol.name) + "::" + id2string(base_name);
953 
954  p.set_identifier(identifier);
955 
956  parameter_symbolt p_symbol;
957 
958  p_symbol.type = p.type();
959  p_symbol.name = identifier;
960  p_symbol.base_name = base_name;
961  p_symbol.location = p.source_location();
962 
963  symbolt *new_p_symbol;
964  move_symbol(p_symbol, new_p_symbol);
965  }
966 }
c_typecheck_baset::do_initializer
virtual void do_initializer(exprt &initializer, const typet &type, bool force_constant)
Definition: c_typecheck_initializer.cpp:26
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
c_typecheck_baset::typecheck_new_symbol
void typecheck_new_symbol(symbolt &symbol)
Definition: c_typecheck_base.cpp:143
to_union_type
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:162
can_cast_expr< symbol_exprt >
bool can_cast_expr< symbol_exprt >(const exprt &base)
Definition: std_expr.h:206
code_typet::has_ellipsis
bool has_ellipsis() const
Definition: std_types.h:611
to_code_with_contract_type
const code_with_contract_typet & to_code_with_contract_type(const typet &type)
Cast a typet to a code_with_contract_typet.
Definition: c_types.h:447
ansi_c_declaration.h
has_subexpr
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:139
ansi_c_declarationt::declarators
const declaratorst & declarators() const
Definition: ansi_c_declaration.h:216
c_typecheck_baset::current_symbol
symbolt current_symbol
Definition: c_typecheck_base.h:71
symbolt::is_macro
bool is_macro
Definition: symbol.h:61
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
symbolt::display_name
const irep_idt & display_name() const
Return language specific display name if present.
Definition: symbol.h:55
typet
The type of an expression, extends irept.
Definition: type.h:28
c_typecheck_base.h
c_typecheck_baset::typecheck_declaration
void typecheck_declaration(ansi_c_declarationt &)
Definition: c_typecheck_base.cpp:704
c_typecheck_baset::to_string
virtual std::string to_string(const exprt &expr)
Definition: c_typecheck_base.cpp:24
irept::find
const irept & find(const irep_idt &name) const
Definition: irep.cpp:106
c_storage_spec.h
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
configt::ansi_ct::os
ost os
Definition: config.h:201
symbol_exprt::typeless
static symbol_exprt typeless(const irep_idt &id)
Generate a symbol_exprt without a proper type.
Definition: std_expr.h:132
configt::ansi_ct::flavourt::VISUAL_STUDIO
@ VISUAL_STUDIO
to_c_enum_type
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
Definition: c_types.h:302
c_storage_spect::section
irep_idt section
Definition: c_storage_spec.h:54
c_storage_spect::is_extern
bool is_extern
Definition: c_storage_spec.h:46
c_typecheck_baset::disallow_subexpr_by_id
void disallow_subexpr_by_id(const exprt &, const irep_idt &, const std::string &) const
Definition: c_typecheck_expr.cpp:4428
exprt
Base class for all expressions.
Definition: expr.h:55
struct_union_typet::componentst
std::vector< componentt > componentst
Definition: std_types.h:140
symbolt::base_name
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
invalid_source_file_exceptiont
Thrown when we can't handle something in an input source file.
Definition: exception_utils.h:171
irep_idt
dstringt irep_idt
Definition: irep.h:37
c_typecheck_baset::move_symbol
void move_symbol(symbolt &symbol, symbolt *&new_symbol)
Definition: c_typecheck_base.cpp:34
c_typecheck_baset::typecheck_type
virtual void typecheck_type(typet &type)
Definition: c_typecheck_type.cpp:35
to_string
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Definition: string_constraint.cpp:58
messaget::eom
static eomt eom
Definition: message.h:297
code_with_contract_typet::ensures_contract
const exprt::operandst & ensures_contract() const
Definition: c_types.h:407
c_storage_spect::is_register
bool is_register
Definition: c_storage_spec.h:46
configt::ansi_c
struct configt::ansi_ct ansi_c
code_with_contract_typet::assigns
const exprt::operandst & assigns() const
Definition: c_types.h:376
configt::ansi_ct::flavourt::ARM
@ ARM
ansi_c_declarationt::get_is_static_assert
bool get_is_static_assert() const
Definition: ansi_c_declaration.h:178
configt::ansi_ct::flavourt::CLANG
@ CLANG
ansi_c_declarationt::set_is_typedef
void set_is_typedef(bool is_typedef)
Definition: ansi_c_declaration.h:83
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
symbolt::pretty_name
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:52
c_typecheck_baset::typecheck_redefinition_non_type
void typecheck_redefinition_non_type(symbolt &old_symbol, symbolt &new_symbol)
Definition: c_typecheck_base.cpp:303
to_code
const codet & to_code(const exprt &expr)
Definition: std_code_base.h:104
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
irept::is_not_nil
bool is_not_nil() const
Definition: irep.h:380
c_typecheck_baset::module
const irep_idt module
Definition: c_typecheck_base.h:69
can_cast_type< code_typet >
bool can_cast_type< code_typet >(const typet &type)
Check whether a reference to a typet is a code_typet.
Definition: std_types.h:731
c_typecheck_baset::asm_label_map
asm_label_mapt asm_label_map
Definition: c_typecheck_base.h:303
to_code_type
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
symbolt::mode
irep_idt mode
Language mode.
Definition: symbol.h:49
c_storage_spect::is_inline
bool is_inline
Definition: c_storage_spec.h:47
messaget::error
mstreamt & error() const
Definition: message.h:399
ansi_c_declarationt::set_is_register
void set_is_register(bool is_register)
Definition: ansi_c_declaration.h:143
c_typecheck_baset::typecheck_function_body
void typecheck_function_body(symbolt &symbol)
Definition: c_typecheck_base.cpp:571
c_typecheck_baset::implicit_typecast_bool
virtual void implicit_typecast_bool(exprt &expr)
Definition: c_typecheck_base.h:118
symbol_table_baset::get_writeable_ref
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
Definition: symbol_table_base.h:121
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
ansi_c_declarationt::set_is_weak
void set_is_weak(bool is_weak)
Definition: ansi_c_declaration.h:193
messaget::mstreamt::source_location
source_locationt source_location
Definition: message.h:247
expr2c.h
expr2c
std::string expr2c(const exprt &expr, const namespacet &ns, const expr2c_configurationt &configuration)
Definition: expr2c.cpp:4046
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
c_typecheck_baset::typecheck_symbol
void typecheck_symbol(symbolt &symbol)
Definition: c_typecheck_base.cpp:48
exprt::find_source_location
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition: expr.cpp:165
symbol_exprt::get_identifier
const irep_idt & get_identifier() const
Definition: std_expr.h:142
std_types.h
code_typet::set_inlined
void set_inlined(bool value)
Definition: std_types.h:670
ansi_c_declarationt::to_symbol
void to_symbol(const ansi_c_declaratort &, symbolt &symbol) const
Definition: ansi_c_declaration.cpp:128
c_storage_spect::asm_label
irep_idt asm_label
Definition: c_storage_spec.h:53
binding_exprt::variablest
std::vector< symbol_exprt > variablest
Definition: std_expr.h:3054
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
symbol_tablet::insert
virtual std::pair< symbolt &, bool > insert(symbolt symbol) override
Author: Diffblue Ltd.
Definition: symbol_table.cpp:17
c_typecheck_baset::symbol_table
symbol_tablet & symbol_table
Definition: c_typecheck_base.h:68
c_typecheck_baset::typecheck_code
virtual void typecheck_code(codet &code)
Definition: c_typecheck_code.cpp:29
irept::swap
void swap(irept &irep)
Definition: irep.h:442
to_symbol_expr
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:222
code_typet
Base type of functions.
Definition: std_types.h:538
symbolt::is_parameter
bool is_parameter
Definition: symbol.h:67
configt::ansi_ct::ost::OS_WIN
@ OS_WIN
irept::id
const irep_idt & id() const
Definition: irep.h:396
c_storage_spect::alias
irep_idt alias
Definition: c_storage_spec.h:50
dstringt::empty
bool empty() const
Definition: dstring.h:88
c_typecheck_baset::typecheck_redefinition_type
void typecheck_redefinition_type(symbolt &old_symbol, symbolt &new_symbol)
Definition: c_typecheck_base.cpp:173
c_storage_spect::is_used
bool is_used
Definition: c_storage_spec.h:47
c_storage_spect
Definition: c_storage_spec.h:17
code_typet::parameters
const parameterst & parameters() const
Definition: std_types.h:655
c_typecheck_baset::parameter_map
id_type_mapt parameter_map
Definition: c_typecheck_base.h:74
code_with_contract_typet::requires_contract
const exprt::operandst & requires_contract() const
Definition: c_types.h:386
is_instantiation_of_flexible_array
static bool is_instantiation_of_flexible_array(const struct_typet &old_type, const struct_typet &new_type)
Definition: c_typecheck_base.cpp:268
c_typecheck_baset::labels_used
std::map< irep_idt, source_locationt > labels_used
Definition: c_typecheck_base.h:173
symbol_tablet::move
virtual bool move(symbolt &symbol, symbolt *&new_symbol) override
Move a symbol into the symbol table.
Definition: symbol_table.cpp:67
c_typecheck_baset::typecheck_expr
virtual void typecheck_expr(exprt &expr)
Definition: c_typecheck_expr.cpp:46
config
configt config
Definition: config.cpp:25
dstringt::as_string
const std::string & as_string() const
Definition: dstring.h:213
ansi_c_declarationt::set_is_thread_local
void set_is_thread_local(bool is_thread_local)
Definition: ansi_c_declaration.h:153
expr_util.h
Deprecated expression utility functions.
configt::ansi_ct::mode
flavourt mode
Definition: config.h:237
code_with_contract_typet
Definition: c_types.h:357
symbolt::value
exprt value
Initial value of symbol.
Definition: symbol.h:34
c_typecheck_baset::typecheck_spec_function_pointer_obeys_contract
virtual void typecheck_spec_function_pointer_obeys_contract(exprt &expr)
Definition: c_typecheck_code.cpp:1028
code_with_contract_typet::has_contract
bool has_contract() const
Definition: c_types.h:369
ansi_c_declarationt
Definition: ansi_c_declaration.h:71
struct_typet
Structure type, corresponds to C style structs.
Definition: std_types.h:230
symbolt::is_extern
bool is_extern
Definition: symbol.h:66
ansi_c_declarationt::set_is_static
void set_is_static(bool is_static)
Definition: ansi_c_declaration.h:103
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
symbolt::location
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
c_typecheck_baset::labels_defined
std::map< irep_idt, source_locationt > labels_defined
Definition: c_typecheck_base.h:173
lambda_exprt
A (mathematical) lambda expression.
Definition: mathematical_expr.h:421
symbolt
Symbol table entry.
Definition: symbol.h:27
c_typecheck_baset::add_parameters_to_symbol_table
void add_parameters_to_symbol_table(symbolt &symbol)
Create symbols for parameter of the code-typed symbol symbol.
Definition: c_typecheck_base.cpp:932
code_with_contract_typet::ensures
const exprt::operandst & ensures() const
Definition: c_types.h:418
symbol_table_baset::symbols
const symbolst & symbols
Read-only field, used to look up symbols given their names.
Definition: symbol_table_base.h:30
exprt::is_constant
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.cpp:27
ansi_c_declarationt::set_is_extern
void set_is_extern(bool is_extern)
Definition: ansi_c_declaration.h:173
symbolt::is_type
bool is_type
Definition: symbol.h:61
c_typecheck_baset::return_type
typet return_type
Definition: c_typecheck_base.h:170
CPROVER_PREFIX
#define CPROVER_PREFIX
Definition: cprover_prefix.h:14
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
ansi_c_declarationt::full_type
typet full_type(const ansi_c_declaratort &) const
Definition: ansi_c_declaration.cpp:94
symbolt::is_static_lifetime
bool is_static_lifetime
Definition: symbol.h:65
c_storage_spect::is_weak
bool is_weak
Definition: c_storage_spec.h:47
code_typet::get_inlined
bool get_inlined() const
Definition: std_types.h:665
config.h
already_typechecked_typet::make_already_typechecked
static void make_already_typechecked(typet &type)
Definition: c_typecheck_base.h:336
configt::ansi_ct::flavourt::GCC
@ GCC
code_typet::return_type
const typet & return_type() const
Definition: std_types.h:645
c_typecheck_baset::check_history_expr_return_value
virtual void check_history_expr_return_value(const exprt &expr, std::string &clause_type)
Checks that no history expr or return_value exists in expr.
Definition: c_typecheck_base.cpp:677
c_typecheck_baset::typecheck_spec_assigns
virtual void typecheck_spec_assigns(exprt::operandst &targets)
Definition: c_typecheck_code.cpp:966
symbol_tablet::erase
virtual void erase(const symbolst::const_iterator &entry) override
Remove a symbol from the symbol table.
Definition: symbol_table.cpp:90
c_storage_spect::is_thread_local
bool is_thread_local
Definition: c_storage_spec.h:47
c_storage_spect::is_static
bool is_static
Definition: c_storage_spec.h:46
symbolt::is_file_local
bool is_file_local
Definition: symbol.h:66
exprt::operands
operandst & operands()
Definition: expr.h:94
symbolt::is_lvalue
bool is_lvalue
Definition: symbol.h:66
type2c
std::string type2c(const typet &type, const namespacet &ns, const expr2c_configurationt &configuration)
Definition: expr2c.cpp:4062
parameter_symbolt
Symbol table entry of function parameter.
Definition: symbol.h:170
irept::remove
void remove(const irep_idt &name)
Definition: irep.cpp:96
exprt::add_source_location
source_locationt & add_source_location()
Definition: expr.h:216
size_type
unsignedbv_typet size_type()
Definition: c_types.cpp:68
symbolt::module
irep_idt module
Name of module the symbol belongs to.
Definition: symbol.h:43
c_storage_spect::is_typedef
bool is_typedef
Definition: c_storage_spec.h:46
messaget::warning
mstreamt & warning() const
Definition: message.h:404
c_typecheck_baset::mode
const irep_idt mode
Definition: c_typecheck_base.h:70
exprt::source_location
const source_locationt & source_location() const
Definition: expr.h:211
c_types.h
symbolt::is_weak
bool is_weak
Definition: symbol.h:67
symbolt::name
irep_idt name
The unique identifier.
Definition: symbol.h:40
code_with_contract_typet::requires
const exprt::operandst & requires() const
Definition: c_types.h:397
symbolt::is_property
bool is_property
Definition: symbol.h:62
c_typecheck_baset::apply_asm_label
void apply_asm_label(const irep_idt &asm_label, symbolt &symbol)
Definition: c_typecheck_base.cpp:612
ansi_c_declarationt::set_is_inline
void set_is_inline(bool is_inline)
Definition: ansi_c_declaration.h:163
ansi_c_declarationt::set_is_used
void set_is_used(bool is_used)
Definition: ansi_c_declaration.h:203
c_typecheck_baset::adjust_function_parameter
virtual void adjust_function_parameter(typet &type) const
Definition: c_typecheck_type.cpp:1655
mathematical_expr.h
codet
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:28