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() << quote_begin << "extern" << quote_end << " symbol "
82 << " should not have an initializer" << eom;
83 }
84 }
85 else if(!is_function && symbol.value.id()==ID_code)
86 {
88 error() << "only functions can have a function body" << eom;
89 throw 0;
90 }
91
92 // set the pretty name
93 if(symbol.is_type && symbol.type.id() == ID_struct)
94 {
95 symbol.pretty_name="struct "+id2string(symbol.base_name);
96 }
97 else if(symbol.is_type && symbol.type.id() == ID_union)
98 {
99 symbol.pretty_name="union "+id2string(symbol.base_name);
100 }
101 else if(symbol.is_type && symbol.type.id() == ID_c_enum)
102 {
103 symbol.pretty_name="enum "+id2string(symbol.base_name);
104 }
105 else
106 {
107 symbol.pretty_name=new_name;
108 }
109
110 if(!symbol.is_type && !symbol.is_extern && symbol.type.id() == ID_empty)
111 {
112 error().source_location = symbol.location;
113 error() << "void-typed symbol not permitted" << eom;
114 throw 0;
115 }
116
117 // see if we have it already
118 symbol_table_baset::symbolst::const_iterator old_it =
119 symbol_table.symbols.find(symbol.name);
120
121 if(old_it==symbol_table.symbols.end())
122 {
123 // just put into symbol_table
124 symbolt *new_symbol;
125 move_symbol(symbol, new_symbol);
126
127 typecheck_new_symbol(*new_symbol);
128 }
129 else
130 {
131 if(old_it->second.is_type!=symbol.is_type)
132 {
134 error() << "redeclaration of '" << symbol.display_name()
135 << "' as a different kind of symbol" << eom;
136 throw 0;
137 }
138
140 if(symbol.is_type)
142 else
143 {
144 if(
145 (!old_it->second.is_static_lifetime || !symbol.is_static_lifetime) &&
146 symbol.type.id() != ID_code)
147 {
148 error().source_location = symbol.location;
149 error() << "redeclaration of '" << symbol.display_name()
150 << "' with no linkage" << eom;
151 throw 0;
152 }
153
155 }
156 }
157}
158
160{
161 if(symbol.is_parameter)
163
164 // check initializer, if needed
165
166 if(symbol.type.id()==ID_code)
167 {
168 if(symbol.value.is_not_nil() &&
169 !symbol.is_macro)
170 {
172 }
173 else if(
174 symbol.is_macro ||
175 !to_code_with_contract_type(symbol.type).has_contract())
176 {
177 // we don't need the identifiers
178 for(auto &parameter : to_code_type(symbol.type).parameters())
179 parameter.set_identifier(irep_idt());
180 }
181 }
182 else if(!symbol.is_macro)
183 {
184 // check the initializer
185 do_initializer(symbol);
186 }
187}
188
190 symbolt &old_symbol,
191 symbolt &new_symbol)
192{
193 const typet &final_old = old_symbol.type;
194 const typet &final_new = new_symbol.type;
195
196 // see if we had something incomplete before
197 if(
198 (final_old.id() == ID_struct &&
199 to_struct_type(final_old).is_incomplete()) ||
200 (final_old.id() == ID_union && to_union_type(final_old).is_incomplete()) ||
201 (final_old.id() == ID_c_enum && to_c_enum_type(final_old).is_incomplete()))
202 {
203 // is the new one complete?
204 if(
205 final_new.id() == final_old.id() &&
206 ((final_new.id() == ID_struct &&
207 !to_struct_type(final_new).is_incomplete()) ||
208 (final_new.id() == ID_union &&
209 !to_union_type(final_new).is_incomplete()) ||
210 (final_new.id() == ID_c_enum &&
211 !to_c_enum_type(final_new).is_incomplete())))
212 {
213 // overwrite location
214 old_symbol.location=new_symbol.location;
215
216 // move body
217 old_symbol.type.swap(new_symbol.type);
218 }
219 else if(new_symbol.type.id()==old_symbol.type.id())
220 return; // ignore
221 else
222 {
223 error().source_location=new_symbol.location;
224 error() << "conflicting definition of type symbol '"
225 << new_symbol.display_name() << '\'' << eom;
226 throw 0;
227 }
228 }
229 else
230 {
231 // see if new one is just a tag
232 if(
233 (final_new.id() == ID_struct &&
234 to_struct_type(final_new).is_incomplete()) ||
235 (final_new.id() == ID_union &&
236 to_union_type(final_new).is_incomplete()) ||
237 (final_new.id() == ID_c_enum &&
238 to_c_enum_type(final_new).is_incomplete()))
239 {
240 if(final_old.id() == final_new.id())
241 {
242 // just ignore silently
243 }
244 else
245 {
246 // arg! new tag type
247 error().source_location=new_symbol.location;
248 error() << "conflicting definition of tag symbol '"
249 << new_symbol.display_name() << '\'' << eom;
250 throw 0;
251 }
252 }
254 final_new.id()==ID_c_enum && final_old.id()==ID_c_enum)
255 {
256 // under Windows, ignore this silently;
257 // MSC doesn't think this is a problem, but GCC complains.
258 }
259 else if(
261 final_new.id() == ID_pointer && final_old.id() == ID_pointer &&
262 to_pointer_type(final_new).base_type().id() == ID_c_enum &&
263 to_pointer_type(final_old).base_type().id() == ID_c_enum)
264 {
265 // under Windows, ignore this silently;
266 // MSC doesn't think this is a problem, but GCC complains.
267 }
268 else
269 {
270 // see if it changed
271 if(new_symbol.type != old_symbol.type)
272 {
273 error().source_location=new_symbol.location;
274 error() << "type symbol '" << new_symbol.display_name()
275 << "' defined twice:\n"
276 << "Original: " << to_string(old_symbol.type) << "\n"
277 << " New: " << to_string(new_symbol.type) << eom;
278 throw 0;
279 }
280 }
281 }
282}
283
285 const struct_typet &old_type,
286 const struct_typet &new_type)
287{
290
291 if(old_components.size() != new_components.size())
292 return false;
293
294 if(old_components.empty())
295 return false;
296
297 for(std::size_t i = 0; i < old_components.size() - 1; ++i)
298 {
299 if(old_components[i].type() != new_components[i].type())
300 return false;
301 }
302
303 if(
304 old_components.back().type().id() != ID_array ||
305 new_components.back().type().id() != ID_array)
306 {
307 return false;
308 }
309
310 const auto &old_array_type = to_array_type(old_components.back().type());
311 const auto &new_array_type = to_array_type(new_components.back().type());
312
313 return old_array_type.element_type() == new_array_type.element_type() &&
316 (old_array_type.size().is_nil() || old_array_type.size() == 0);
317}
318
320 symbolt &old_symbol,
321 symbolt &new_symbol)
322{
323 const typet &final_old = old_symbol.type;
324 const typet &initial_new = new_symbol.type;
325
326 if(
327 final_old.id() == ID_array &&
328 to_array_type(final_old).size().is_not_nil() &&
329 initial_new.id() == ID_array &&
330 to_array_type(initial_new).size().is_nil() &&
331 to_array_type(final_old).element_type() ==
332 to_array_type(initial_new).element_type())
333 {
334 // this is ok, just use old type
335 new_symbol.type=old_symbol.type;
336 }
337 else if(
338 final_old.id() == ID_array && to_array_type(final_old).size().is_nil() &&
339 initial_new.id() == ID_array &&
340 to_array_type(initial_new).size().is_not_nil() &&
341 to_array_type(final_old).element_type() ==
342 to_array_type(initial_new).element_type())
343 {
344 // update the type to enable the use of sizeof(x) on the
345 // right-hand side of a definition of x
346 old_symbol.type=new_symbol.type;
347 }
348
349 // do initializer, this may change the type
350 if(new_symbol.type.id() != ID_code && !new_symbol.is_macro)
351 do_initializer(new_symbol);
352
353 const typet &final_new = new_symbol.type;
354
355 // K&R stuff?
356 if(old_symbol.type.id()==ID_KnR)
357 {
358 // check the type
359 if(final_new.id()==ID_code)
360 {
361 error().source_location=new_symbol.location;
362 error() << "function type not allowed for K&R function parameter"
363 << eom;
364 throw 0;
365 }
366
367 // fix up old symbol -- we now got the type
368 old_symbol.type=new_symbol.type;
369 return;
370 }
371
372 if(final_new.id()==ID_code)
373 {
374 if(final_old.id()!=ID_code)
375 {
376 error().source_location=new_symbol.location;
377 error() << "function symbol '" << new_symbol.display_name()
378 << "' redefined with a different type:\n"
379 << "Original: " << to_string(old_symbol.type) << "\n"
380 << " New: " << to_string(new_symbol.type) << eom;
381 throw 0;
382 }
383
384 code_typet &old_ct=to_code_type(old_symbol.type);
385 code_typet &new_ct=to_code_type(new_symbol.type);
386
387 if(
388 old_ct.return_type() != new_ct.return_type() &&
389 !old_ct.get_bool(ID_C_incomplete) &&
390 new_ct.return_type().id() != ID_constructor &&
391 new_ct.return_type().id() != ID_destructor)
392 {
393 if(
394 old_ct.return_type().id() == ID_constructor ||
395 old_ct.return_type().id() == ID_destructor)
396 {
397 new_ct = old_ct;
398 }
399 else
400 {
402 "function symbol '" + id2string(new_symbol.display_name()) +
403 "' redefined with a different type:\n" +
404 "Original: " + to_string(old_symbol.type) + "\n" +
405 " New: " + to_string(new_symbol.type),
406 new_symbol.location};
407 }
408 }
409 const bool inlined = old_ct.get_inlined() || new_ct.get_inlined();
410
411 if(old_ct.has_ellipsis() && !new_ct.has_ellipsis())
413 else if(!old_ct.has_ellipsis() && new_ct.has_ellipsis())
414 {
416 {
417 error().source_location = new_symbol.location;
418 error() << "code contract on incomplete function re-declaration" << eom;
419 throw 0;
420 }
422 }
423
424 if(inlined)
425 {
426 old_ct.set_inlined(true);
427 new_ct.set_inlined(true);
428 }
429
430 // do body
431
432 if(new_symbol.value.is_not_nil())
433 {
434 if(old_symbol.value.is_not_nil())
435 {
436 // gcc allows re-definition if the first
437 // definition is marked as "extern inline"
438
439 if(
440 old_ct.get_inlined() &&
445 {
446 // overwrite "extern inline" properties
447 old_symbol.is_extern=new_symbol.is_extern;
448 old_symbol.is_file_local=new_symbol.is_file_local;
449
450 // remove parameter declarations to avoid conflicts
451 for(const auto &old_parameter : old_ct.parameters())
452 {
453 const irep_idt &identifier = old_parameter.get_identifier();
454
455 symbol_table_baset::symbolst::const_iterator p_s_it =
456 symbol_table.symbols.find(identifier);
457 if(p_s_it!=symbol_table.symbols.end())
459 }
460 }
461 else
462 {
463 error().source_location=new_symbol.location;
464 error() << "function body '" << new_symbol.display_name()
465 << "' defined twice" << eom;
466 throw 0;
467 }
468 }
469 else if(inlined)
470 {
471 // preserve "extern inline" properties
472 old_symbol.is_extern=new_symbol.is_extern;
473 old_symbol.is_file_local=new_symbol.is_file_local;
474 }
475 else if(new_symbol.is_weak)
476 {
477 // weak symbols
478 old_symbol.is_weak=true;
479 }
480
481 if(new_symbol.is_macro)
482 old_symbol.is_macro=true;
483 else
484 typecheck_function_body(new_symbol);
485
486 // overwrite location
487 old_symbol.location=new_symbol.location;
488
489 // move body
490 old_symbol.value.swap(new_symbol.value);
491
492 // overwrite type (because of parameter names)
493 old_symbol.type=new_symbol.type;
494 }
496 {
497 // overwrite type to add contract, but keep the old parameter identifiers
498 // (if any)
499 auto new_parameters_it = new_ct.parameters().begin();
500 for(auto &p : old_ct.parameters())
501 {
502 if(new_parameters_it != new_ct.parameters().end())
503 {
504 new_parameters_it->set_identifier(p.get_identifier());
506 }
507 }
508
509 old_symbol.type = new_symbol.type;
510 }
511
512 return;
513 }
514
516 {
517 if(
518 final_old.id() == ID_array && to_array_type(final_old).size().is_nil() &&
519 final_new.id() == ID_array &&
520 to_array_type(final_new).size().is_not_nil() &&
521 to_array_type(final_old).element_type() ==
522 to_array_type(final_new).element_type())
523 {
524 old_symbol.type=new_symbol.type;
525 }
526 else if(
527 final_old.id() == ID_pointer &&
528 to_pointer_type(final_old).base_type().id() == ID_code &&
529 to_code_type(to_pointer_type(final_old).base_type()).has_ellipsis() &&
530 final_new.id() == ID_pointer &&
531 to_pointer_type(final_new).base_type().id() == ID_code)
532 {
533 // to allow
534 // int (*f) ();
535 // int (*f) (int)=0;
536 old_symbol.type=new_symbol.type;
537 }
538 else if(
539 final_old.id() == ID_pointer &&
540 to_pointer_type(final_old).base_type().id() == ID_code &&
541 final_new.id() == ID_pointer &&
542 to_pointer_type(final_new).base_type().id() == ID_code &&
543 to_code_type(to_pointer_type(final_new).base_type()).has_ellipsis())
544 {
545 // to allow
546 // int (*f) (int)=0;
547 // int (*f) ();
548 }
549 else if(
550 final_old.id() == ID_struct_tag && final_new.id() == ID_struct_tag &&
554 {
555 old_symbol.type = new_symbol.type;
556 }
557 else
558 {
559 error().source_location=new_symbol.location;
560 error() << "symbol '" << new_symbol.display_name()
561 << "' redefined with a different type:\n"
562 << "Original: " << to_string(old_symbol.type) << "\n"
563 << " New: " << to_string(new_symbol.type) << eom;
564 throw 0;
565 }
566 }
567 else // finals are equal
568 {
569 }
570
571 // do value
572 if(new_symbol.value.is_not_nil())
573 {
574 // see if we already have one
575 if(old_symbol.value.is_not_nil())
576 {
577 if(
578 new_symbol.is_macro && final_new.id() == ID_c_enum &&
579 old_symbol.value.is_constant() && new_symbol.value.is_constant() &&
580 old_symbol.value.get(ID_value) == new_symbol.value.get(ID_value))
581 {
582 // ignore
583 }
584 else
585 {
587 warning() << "symbol '" << new_symbol.display_name()
588 << "' already has an initial value" << eom;
589 }
590 }
591 else
592 {
593 old_symbol.value=new_symbol.value;
594 old_symbol.type=new_symbol.type;
595 old_symbol.is_macro=new_symbol.is_macro;
596 }
597 }
598
599 // take care of some flags
600 if(old_symbol.is_extern && !new_symbol.is_extern)
601 old_symbol.location=new_symbol.location;
602
603 old_symbol.is_extern=old_symbol.is_extern && new_symbol.is_extern;
604
605 // We should likely check is_volatile and
606 // is_thread_local for consistency. GCC complains if these
607 // mismatch.
608}
609
611{
612 if(symbol.value.id() != ID_code)
613 {
614 error().source_location = symbol.location;
615 error() << "function '" << symbol.name << "' is initialized with "
616 << symbol.value.id() << eom;
617 throw 0;
618 }
619
621
622 // reset labels
623 labels_used.clear();
624 labels_defined.clear();
625
626 // A function declaration int foo(); does not specify the parameter list, but
627 // a function definition int foo() { ... } does fix the parameter list to be
628 // empty.
629 if(code_type.parameters().empty() && code_type.has_ellipsis())
630 code_type.remove_ellipsis();
631
632 // fix type
633 symbol.value.type()=code_type;
634
635 // set return type
636 return_type=code_type.return_type();
637
638 // Add the parameter declarations into the symbol table
640
641 // typecheck the body code
643
644 // check the labels
645 for(const auto &label : labels_used)
646 {
647 if(labels_defined.find(label.first) == labels_defined.end())
648 {
649 error().source_location = label.second;
650 error() << "branching label '" << label.first
651 << "' is not defined in function" << eom;
652 throw 0;
653 }
654 }
655}
656
658 const irep_idt &asm_label,
659 symbolt &symbol)
660{
661 const irep_idt orig_name=symbol.name;
662
663 // restrict renaming to functions and global variables;
664 // procedure-local ones would require fixing the scope, as we
665 // do for parameters below
666 if(!asm_label.empty() &&
667 !symbol.is_type &&
668 (symbol.type.id()==ID_code || symbol.is_static_lifetime))
669 {
670 symbol.name=asm_label;
671 symbol.base_name=asm_label;
672 // asm renaming may be combined with varied return types - make sure the
673 // actual definition sets the final type
674 if(symbol.type.id() == ID_code)
675 symbol.type.set(ID_C_incomplete, true);
676 }
677
678 if(symbol.name!=orig_name)
679 {
680 if(!asm_label_map.insert(
681 std::make_pair(orig_name, asm_label)).second)
682 {
683 if(asm_label_map[orig_name]!=asm_label)
684 {
686 error() << "replacing asm renaming " << asm_label_map[orig_name]
687 << " by " << asm_label << eom;
688 throw 0;
689 }
690 }
691 }
692 else if(asm_label.empty())
693 {
694 asm_label_mapt::const_iterator entry=
695 asm_label_map.find(symbol.name);
696 if(entry!=asm_label_map.end())
697 {
698 symbol.name=entry->second;
699 symbol.base_name=entry->second;
700 }
701 }
702
703 if(symbol.name!=orig_name &&
704 symbol.type.id()==ID_code &&
705 symbol.value.is_not_nil() && !symbol.is_macro)
706 {
707 const code_typet &code_type=to_code_type(symbol.type);
708
709 for(const auto &p : code_type.parameters())
710 {
711 const irep_idt &p_bn = p.get_base_name();
712 if(p_bn.empty())
713 continue;
714
717
718 if(!asm_label_map.insert(
719 std::make_pair(p_id, p_new_id)).second)
720 {
722 }
723 }
724 }
725}
726
728 const exprt &expr,
729 std::string &clause_type)
730{
732 expr, ID_old, CPROVER_PREFIX "old is not allowed in " + clause_type + ".");
734 expr,
736 CPROVER_PREFIX "loop_entry is not allowed in " + clause_type + ".");
737
738 const irep_idt id = CPROVER_PREFIX "return_value";
739 auto pred = [&](const exprt &expr) {
741 return false;
742
743 return to_symbol_expr(expr).identifier() == id;
744 };
745
746 if(!has_subexpr(expr, pred))
747 return;
748
750 id2string(id) + " is not allowed in " + id2string(clause_type) + ".",
751 expr.source_location());
752}
753
755 const exprt &expr,
756 std::string &clause_type)
757{
758 const irep_idt id = CPROVER_PREFIX "was_freed";
759
760 auto pred = [&](const exprt &expr) {
762 return false;
763
764 return to_symbol_expr(expr).identifier() == id;
765 };
766
767 if(has_subexpr(expr, pred))
768 {
770 id2string(id) + " is not allowed in " + clause_type + ".",
771 expr.source_location());
772 }
773}
774
776 ansi_c_declarationt &declaration)
777{
778 if(declaration.get_is_static_assert())
779 {
781 code.add_source_location() = declaration.source_location();
782 code.operands().swap(declaration.operands());
783 typecheck_code(code);
784 }
785 else
786 {
787 // get storage spec
788 c_storage_spect c_storage_spec(declaration.type());
789
790 // first typecheck the type of the declaration
791 typecheck_type(declaration.type());
792
793 // mark as 'already typechecked'
795
796 // Now do declarators, if any.
797 for(auto &declarator : declaration.declarators())
798 {
799 c_storage_spect full_spec(declaration.full_type(declarator));
800 full_spec|=c_storage_spec;
801
802 declaration.set_is_inline(full_spec.is_inline);
803 declaration.set_is_static(full_spec.is_static);
804 declaration.set_is_extern(full_spec.is_extern);
805 declaration.set_is_thread_local(full_spec.is_thread_local);
806 declaration.set_is_register(full_spec.is_register);
807 declaration.set_is_typedef(full_spec.is_typedef);
808 declaration.set_is_weak(full_spec.is_weak);
809
810 symbolt symbol = declaration.to_symbol(declarator);
811 current_symbol=symbol;
812
813 // now check other half of type
814 typecheck_type(symbol.type);
815
816 if(!full_spec.alias.empty())
817 {
818 if(symbol.value.is_not_nil())
819 {
821 error() << "alias attribute cannot be used with a body"
822 << eom;
823 throw 0;
824 }
825
826 // alias function need not have been declared yet, thus
827 // can't lookup
828 // also cater for renaming/placement in sections
829 const auto &renaming_entry = asm_label_map.find(full_spec.alias);
830 if(renaming_entry == asm_label_map.end())
831 symbol.value = symbol_exprt::typeless(full_spec.alias);
832 else
834 symbol.is_macro=true;
835 }
836
837 if(full_spec.is_used && symbol.is_file_local)
838 {
839 // GCC __attribute__((__used__)) - do not treat those as file-local, but
840 // make sure the name is unique
841 symbol.is_file_local = false;
842
844 if(!full_spec.asm_label.empty())
845 symbol_for_renaming.name = full_spec.asm_label;
846 full_spec.asm_label = djb_manglert{}(
848 id2string(symbol_for_renaming.location.get_file()));
849 }
850
851 if(full_spec.section.empty())
852 apply_asm_label(full_spec.asm_label, symbol);
853 else
854 {
855 // section name is not empty, do a bit of parsing
856 std::string asm_name = id2string(full_spec.section);
857
858 if(asm_name[0] == '.')
859 {
860 std::string::size_type primary_section = asm_name.find('.', 1);
861
862 if(primary_section != std::string::npos)
864 }
865
866 asm_name += "$$";
867
868 if(!full_spec.asm_label.empty())
869 asm_name+=id2string(full_spec.asm_label);
870 else
871 asm_name+=id2string(symbol.name);
872
873 apply_asm_label(asm_name, symbol);
874 }
875
876 irep_idt identifier=symbol.name;
877 declarator.set_name(identifier);
878
879 typecheck_symbol(symbol);
880
881 // check the contract, if any
882 symbolt &new_symbol = symbol_table.get_writeable_ref(identifier);
883 if(
884 new_symbol.type.id() == ID_code &&
885 to_code_with_contract_type(new_symbol.type).has_contract())
886 {
889
890 // ensure parameter declarations are available for type checking to
891 // succeed
893
894 const auto &return_type = code_type.return_type();
895 if(return_type.id() != ID_empty)
896 {
897 parameter_map[CPROVER_PREFIX "return_value"] = return_type;
898 temporary_parameter_symbols.emplace_back(
899 CPROVER_PREFIX "return_value", return_type);
900 }
901
902 std::size_t anon_counter = 0;
903 for(auto &p : code_type.parameters())
904 {
905 // may be anonymous
906 if(p.get_base_name().empty())
907 p.set_base_name("#anon" + std::to_string(anon_counter++));
908
909 // produce identifier
910 const irep_idt &base_name = p.get_base_name();
912 id2string(identifier) + "::" + id2string(base_name);
913
914 p.set_identifier(parameter_identifier);
915
919 temporary_parameter_symbols.emplace_back(
920 parameter_identifier, p.type());
921 }
922
923 for(auto &c_requires : code_type.c_requires())
924 {
925 typecheck_expr(c_requires);
926 implicit_typecast_bool(c_requires);
927 std::string clause_type = "preconditions";
929 check_was_freed(c_requires, clause_type);
931 lambda.add_source_location() = c_requires.source_location();
932 c_requires.swap(lambda);
933 }
934
936 for(auto &assigns : code_type.c_assigns())
937 {
938 std::string clause_type = "assigns clauses";
941 lambda.add_source_location() = assigns.source_location();
942 assigns.swap(lambda);
943 }
944
946 for(auto &frees : code_type.c_frees())
947 {
949 lambda.add_source_location() = frees.source_location();
950 frees.swap(lambda);
951 }
952
953 for(auto &ensures : code_type.c_ensures())
954 {
958 ensures,
960 CPROVER_PREFIX "loop_entry is not allowed in postconditions.");
962 lambda.add_source_location() = ensures.source_location();
963 ensures.swap(lambda);
964 }
965
967 parameter_map.erase(parameter_sym.identifier());
968
969 // create a contract symbol
971 contract.name = "contract::" + id2string(new_symbol.name);
972 contract.base_name = new_symbol.base_name;
973 contract.pretty_name = new_symbol.pretty_name;
974 contract.is_property = true;
975 contract.type = code_type;
976 contract.mode = new_symbol.mode;
977 contract.module = module;
978 contract.location = new_symbol.location;
979
980 auto entry = symbol_table.insert(std::move(contract));
981 if(!entry.second)
982 {
983 error().source_location = new_symbol.location;
984 error() << "contract '" << new_symbol.display_name()
985 << "' already set at " << entry.first.location.as_string()
986 << eom;
987 throw 0;
988 }
989
990 // Remove the contract from the original symbol as we have created a
991 // dedicated contract symbol.
992 new_symbol.type.remove(ID_C_spec_assigns);
993 new_symbol.type.remove(ID_C_spec_frees);
994 new_symbol.type.remove(ID_C_spec_ensures);
995 new_symbol.type.remove(ID_C_spec_requires);
996 }
997 }
998 }
999}
1000
1002{
1004
1006
1007 unsigned anon_counter = 0;
1008
1009 // Add the parameter declarations into the symbol table.
1010 for(auto &p : code_type.parameters())
1011 {
1012 // may be anonymous
1013 if(p.get_base_name().empty())
1014 {
1015 irep_idt base_name = "#anon" + std::to_string(anon_counter++);
1016 p.set_base_name(base_name);
1017 }
1018
1019 // produce identifier
1020 irep_idt base_name = p.get_base_name();
1021 irep_idt identifier = id2string(symbol.name) + "::" + id2string(base_name);
1022
1023 p.set_identifier(identifier);
1024
1026
1027 p_symbol.type = p.type();
1028 p_symbol.name = identifier;
1029 p_symbol.base_name = base_name;
1030 p_symbol.location = p.source_location();
1031
1034 }
1035}
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:566
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:3172
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:582
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:101
Base class for all expressions.
Definition expr.h:57
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition expr.cpp:68
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:213
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
const source_locationt & source_location() const
Definition expr.h:236
source_locationt & add_source_location()
Definition expr.h:241
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
void set(const irep_idt &name, const irep_idt &value)
Definition irep.h:412
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
static const commandt quote_begin
Start quoted text.
Definition message.h:389
mstreamt & error() const
Definition message.h:401
mstreamt & warning() const
Definition message.h:406
static const commandt quote_end
End quoted text.
Definition message.h:393
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:49
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:230
std::vector< componentt > componentst
Definition std_types.h:139
static symbol_exprt typeless(const irep_idt &id)
Generate a symbol_exprt without a proper type.
Definition std_expr.h:149
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:4198
std::string type2c(const typet &type, const namespacet &ns, const expr2c_configurationt &configuration)
Definition expr2c.cpp:4214
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:221
Pre-defined types.
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:787
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:307
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:517
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:887
Author: Diffblue Ltd.