CBMC
Loading...
Searching...
No Matches
c_typecheck_base.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: ANSI-C Conversion / Type Checking
4
5Author: 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>
19#include <util/std_types.h>
21
23
24#include "ansi_c_declaration.h"
25#include "c_storage_spec.h"
26#include "expr2c.h"
27
28std::string c_typecheck_baset::to_string(const exprt &expr)
29{
30 return expr2c(expr, *this);
31}
32
33std::string c_typecheck_baset::to_string(const typet &type)
34{
35 return type2c(type, *this);
36}
37
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
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
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 {
133 error() << "redeclaration of '" << symbol.display_name()
134 << "' as a different kind of symbol" << eom;
135 throw 0;
136 }
137
139 if(symbol.is_type)
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
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 {
171 }
172 else if(
173 symbol.is_macro ||
174 !to_code_with_contract_type(symbol.type).has_contract())
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{
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() &&
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())
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 }
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())
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 }
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());
505 }
506 }
507
508 old_symbol.type = new_symbol.type;
509 }
510
511 return;
512 }
513
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 &&
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
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
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 {
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
712
713 if(!asm_label_map.insert(
714 std::make_pair(p_id, p_new_id)).second)
715 {
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,
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) {
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) {
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 {
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 {
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
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
839 if(!full_spec.asm_label.empty())
840 symbol_for_renaming.name = full_spec.asm_label;
841 full_spec.asm_label = djb_manglert{}(
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)
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 &&
880 to_code_with_contract_type(new_symbol.type).has_contract())
881 {
884
885 // ensure parameter declarations are available for type checking to
886 // succeed
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();
907 id2string(identifier) + "::" + id2string(base_name);
908
909 p.set_identifier(parameter_identifier);
910
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";
924 check_was_freed(c_requires, clause_type);
926 lambda.add_source_location() = c_requires.source_location();
927 c_requires.swap(lambda);
928 }
929
931 for(auto &assigns : code_type.c_assigns())
932 {
933 std::string clause_type = "assigns clauses";
936 lambda.add_source_location() = assigns.source_location();
937 assigns.swap(lambda);
938 }
939
941 for(auto &frees : code_type.c_frees())
942 {
944 lambda.add_source_location() = frees.source_location();
945 frees.swap(lambda);
946 }
947
948 for(auto &ensures : code_type.c_ensures())
949 {
953 ensures,
955 CPROVER_PREFIX "loop_entry is not allowed in postconditions.");
957 lambda.add_source_location() = ensures.source_location();
958 ensures.swap(lambda);
959 }
960
962 parameter_map.erase(parameter_sym.get_identifier());
963
964 // create a contract symbol
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
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
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
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 union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition c_types.h:184
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
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
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
const declaratorst & declarators() const
void set_is_register(bool is_register)
void set_is_inline(bool is_inline)
typet full_type(const ansi_c_declaratort &) 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:3236
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
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)
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)
const irep_idt const irep_idt mode
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
Data structure for representing an arbitrary statement in a program.
struct configt::ansi_ct ansi_c
Mangle identifiers by hashing their working directory with djb2 hash.
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
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
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:212
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
const source_locationt & source_location() const
Definition expr.h:231
source_locationt & add_source_location()
Definition expr.h:236
Thrown when we can't handle something in an input source file.
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:372
void swap(irept &irep)
Definition irep.h:434
const irep_idt & id() const
Definition irep.h:388
A (mathematical) lambda expression.
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
Symbol table entry of function parameterThis is a symbol generated as part of type checking.
Definition symbol.h:179
Structure type, corresponds to C style structs.
Definition std_types.h:231
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
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
virtual bool move(symbolt &symbol, symbolt *&new_symbol)=0
virtual std::pair< symbolt &, bool > insert(symbolt symbol)=0
Move or copy a new symbol to the symbol table.
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.
Symbol table entry.
Definition symbol.h:28
bool is_extern
Definition symbol.h:74
bool is_macro
Definition symbol.h:62
bool is_file_local
Definition symbol.h:73
bool is_static_lifetime
Definition symbol.h:70
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
irep_idt irep_idt base_name
Name of module the symbol belongs to.
Definition symbol.h:46
const irep_idt & display_name() const
Return language specific display name if present.
Definition symbol.h:55
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:4155
std::string type2c(const typet &type, const namespacet &ns, const expr2c_configurationt &configuration)
Definition expr2c.cpp:4171
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
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:44
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.
#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
Pre-defined types.
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
Author: Diffblue Ltd.