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