Skip to content

Commit 0048f4c

Browse files
committed
Updates type checking to handle new assigns-clause constructs
Signed-off-by: Felipe R. Monteiro <[email protected]>
1 parent db2415f commit 0048f4c

File tree

2 files changed

+120
-15
lines changed

2 files changed

+120
-15
lines changed

src/ansi-c/c_typecheck_base.cpp

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,44 @@ void c_typecheck_baset::typecheck_new_symbol(symbolt &symbol)
156156
}
157157
else
158158
{
159-
// we don't need the identifiers
160-
for(auto &parameter : to_code_type(symbol.type).parameters())
161-
parameter.set_identifier(irep_idt());
159+
code_typet &code_type = to_code_type(symbol.type);
160+
161+
// Add the parameter declarations into the symbol table.
162+
for(auto &parameter : code_type.parameters())
163+
{
164+
std::string symbol_name = id2string(symbol.name);
165+
166+
// CPROVER primitives, anonymous, builtin and atomics do not need identifiers
167+
if(
168+
symbol_name.find("__atomic_") != std::string::npos ||
169+
symbol_name.find("__builtin_") != std::string::npos ||
170+
symbol_name.find("__CPROVER_") != std::string::npos ||
171+
symbol_name.find("__VERIFIER_") != std::string::npos ||
172+
parameter.get_base_name().empty())
173+
{
174+
parameter.set_identifier(irep_idt());
175+
}
176+
else
177+
{
178+
// produce identifier
179+
irep_idt identifier =
180+
symbol_name + "::" + id2string(parameter.get_base_name());
181+
parameter.set_identifier(identifier);
182+
183+
parameter_symbolt parameter_symbol;
184+
parameter_symbol.type = parameter.type();
185+
parameter_symbol.name = identifier;
186+
parameter_symbol.base_name = parameter.get_base_name();
187+
parameter_symbol.location = parameter.source_location();
188+
189+
symbolt *new_parameter_symbol;
190+
191+
symbol.mode = mode;
192+
symbol.module = module;
193+
194+
move_symbol(parameter_symbol, new_parameter_symbol);
195+
}
196+
}
162197
}
163198
}
164199
else if(!symbol.is_macro)
@@ -341,7 +376,6 @@ void c_typecheck_baset::typecheck_redefinition_non_type(
341376
}
342377

343378
// do body
344-
345379
if(new_symbol.value.is_not_nil())
346380
{
347381
if(old_symbol.value.is_not_nil())
@@ -379,6 +413,21 @@ void c_typecheck_baset::typecheck_redefinition_non_type(
379413
throw 0;
380414
}
381415
}
416+
else if(old_ct.parameters().size() > 0) // previous declaration
417+
{
418+
// remove parameter declarations to avoid conflicts
419+
for(const auto &old_parameter : old_ct.parameters())
420+
{
421+
const irep_idt &identifier = old_parameter.get_identifier();
422+
423+
symbol_tablet::symbolst::const_iterator parameter_symbol_it =
424+
symbol_table.symbols.find(identifier);
425+
if(parameter_symbol_it != symbol_table.symbols.end())
426+
{
427+
symbol_table.erase(parameter_symbol_it);
428+
}
429+
}
430+
}
382431
else if(inlined)
383432
{
384433
// preserve "extern inline" properties
@@ -402,6 +451,29 @@ void c_typecheck_baset::typecheck_redefinition_non_type(
402451
// move body
403452
old_symbol.value.swap(new_symbol.value);
404453

454+
// Copy contract over, if it exists
455+
const code_typet &old_type = to_code_type(old_symbol.type);
456+
exprt old_assigns =
457+
static_cast<const exprt &>(old_type.find(ID_C_spec_assigns));
458+
exprt old_requires =
459+
static_cast<const exprt &>(old_type.find(ID_C_spec_requires));
460+
exprt old_ensures =
461+
static_cast<const exprt &>(old_type.find(ID_C_spec_ensures));
462+
if(old_assigns.is_not_nil())
463+
{
464+
new_symbol.type.get_named_sub().add(
465+
ID_C_spec_assigns, std::move(old_assigns));
466+
}
467+
if(old_requires.is_not_nil())
468+
{
469+
new_symbol.type.get_named_sub().add(
470+
ID_C_spec_requires, std::move(old_requires));
471+
}
472+
if(old_ensures.is_not_nil())
473+
{
474+
new_symbol.type.move_to_named_sub(ID_C_spec_ensures, old_ensures);
475+
}
476+
405477
// overwrite type (because of parameter names)
406478
old_symbol.type=new_symbol.type;
407479
}
@@ -729,13 +801,12 @@ void c_typecheck_baset::typecheck_declaration(
729801
declarator.set_name(identifier);
730802

731803
// If the declarator is for a function definition, typecheck it.
804+
typecheck_symbol(symbol);
732805
if(can_cast_type<code_typet>(declarator.type()))
733806
{
734807
typecheck_assigns(to_code_type(declarator.type()), contract);
735808
}
736809

737-
typecheck_symbol(symbol);
738-
739810
// add code contract (if any); we typecheck this after the
740811
// function body done above, so as to have parameter symbols
741812
// available
@@ -754,15 +825,15 @@ void c_typecheck_baset::typecheck_declaration(
754825
typecheck_spec_expr(static_cast<codet &>(contract), ID_C_spec_ensures);
755826
parameter_map.clear();
756827

757-
irept assigns_to_add = contract.find(ID_C_spec_assigns);
758-
if(assigns_to_add.is_not_nil())
759-
new_symbol.type.add(ID_C_spec_assigns) = assigns_to_add;
760-
irept requires_to_add = contract.find(ID_C_spec_requires);
761-
if(requires_to_add.is_not_nil())
762-
new_symbol.type.add(ID_C_spec_requires) = requires_to_add;
763-
irept ensures_to_add = contract.find(ID_C_spec_ensures);
764-
if(ensures_to_add.is_not_nil())
765-
new_symbol.type.add(ID_C_spec_ensures) = ensures_to_add;
828+
if(contract.find(ID_C_spec_assigns).is_not_nil())
829+
new_symbol.type.add(ID_C_spec_assigns) =
830+
contract.find(ID_C_spec_assigns);
831+
if(contract.find(ID_C_spec_requires).is_not_nil())
832+
new_symbol.type.add(ID_C_spec_requires) =
833+
contract.find(ID_C_spec_requires);
834+
if(contract.find(ID_C_spec_ensures).is_not_nil())
835+
new_symbol.type.add(ID_C_spec_ensures) =
836+
contract.find(ID_C_spec_ensures);
766837
}
767838
}
768839
}

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,40 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
491491
{
492492
// already type checked
493493
}
494+
else if(expr.id() == ID_int_range)
495+
{
496+
// already type checked
497+
exprt &lower = to_int_range_exprt(expr).op0();
498+
exprt &upper = to_int_range_exprt(expr).op1();
499+
500+
if(lower.id() == ID_constant || lower.id() == ID_identifier)
501+
{
502+
dstringt c_type = lower.type().get(ID_C_c_type);
503+
if(c_type != ID_signed_int.c_str() && c_type != ID_unsigned_int.c_str())
504+
{
505+
error().source_location = expr.source_location();
506+
error() << "Lower bound of range should be an integer, but got: "
507+
<< lower.type().pretty() << eom;
508+
throw 0;
509+
}
510+
}
511+
512+
if(upper.id() == ID_constant || upper.id() == ID_identifier)
513+
{
514+
dstringt upper_type = upper.type().get(ID_C_c_type);
515+
if(upper_type != ID_signed_int.c_str() && upper_type != ID_unsigned_int.c_str())
516+
{
517+
error().source_location = expr.source_location();
518+
error() << "Upper bound of range should be an integer, but got: "
519+
<< upper.pretty() << eom;
520+
throw 0;
521+
}
522+
}
523+
}
524+
else if(expr.id() == ID_array_range)
525+
{
526+
// Already type checked
527+
}
494528
else
495529
{
496530
error().source_location = expr.source_location();

0 commit comments

Comments
 (0)