void ansi_c_typecheckt::typecheck() { for(ansi_c_parse_treet::itemst::iterator it=parse_tree.items.begin(); it!=parse_tree.items.end(); it++) { if(it->id()==ID_declaration) { symbolt symbol; to_ansi_c_declaration(*it).to_symbol(symbol); typecheck_symbol(symbol); } else if(it->id()==ID_initializer) { } else assert(false); } }
void c_typecheck_baset::typecheck_code_type(code_typet &type) { // the return type is still 'subtype()' type.return_type()=type.subtype(); type.remove_subtype(); code_typet::parameterst ¶meters=type.parameters(); // if we don't have any parameters, we assume it's (...) if(parameters.empty()) { type.make_ellipsis(); } else // we do have parameters { // is the last one ellipsis? if(type.parameters().back().id()==ID_ellipsis) { type.make_ellipsis(); type.parameters().pop_back(); } parameter_map.clear(); for(auto ¶m : type.parameters()) { // turn the declarations into parameters if(param.id()==ID_declaration) { ansi_c_declarationt &declaration= to_ansi_c_declaration(param); code_typet::parametert parameter; // first fix type typet &type=parameter.type(); type=declaration.full_type(declaration.declarator()); std::list<codet> tmp_clean_code; tmp_clean_code.swap(clean_code); // ignore side-effects typecheck_type(type); tmp_clean_code.swap(clean_code); adjust_function_parameter(type); // adjust the identifier irep_idt identifier=declaration.declarator().get_name(); // abstract or not? if(identifier==irep_idt()) { // abstract parameter.add_source_location()=declaration.type().source_location(); } else { // make visible now, later parameters might use it parameter_map[identifier]=type; parameter.set_base_name(declaration.declarator().get_base_name()); parameter.add_source_location()= declaration.declarator().source_location(); } // put the parameter in place of the declaration param.swap(parameter); } } parameter_map.clear(); if(parameters.size()==1 && follow(parameters[0].type()).id()==ID_empty) { // if we just have one parameter of type void, remove it parameters.clear(); } } typecheck_type(type.return_type()); // 6.7.6.3: // "A function declarator shall not specify a return type that // is a function type or an array type." const typet &return_type=follow(type.return_type()); if(return_type.id()==ID_array) { error().source_location=type.source_location(); error() << "function must not return array" << eom; throw 0; } if(return_type.id()==ID_code) { error().source_location=type.source_location(); error() << "function must not return function type" << eom; throw 0; } }
void c_typecheck_baset::typecheck_compound_body( struct_union_typet &type) { struct_union_typet::componentst &components=type.components(); struct_union_typet::componentst old_components; old_components.swap(components); // We get these as declarations! for(auto &decl : old_components) { // the arguments are member declarations or static assertions assert(decl.id()==ID_declaration); ansi_c_declarationt &declaration= to_ansi_c_declaration(static_cast<exprt &>(decl)); if(declaration.get_is_static_assert()) { struct_union_typet::componentt new_component; new_component.id(ID_static_assert); new_component.add_source_location()=declaration.source_location(); new_component.operands().swap(declaration.operands()); assert(new_component.operands().size()==2); components.push_back(new_component); } else { // do first half of type typecheck_type(declaration.type()); make_already_typechecked(declaration.type()); for(const auto &declarator : declaration.declarators()) { struct_union_typet::componentt new_component; new_component.add_source_location()= declarator.source_location(); new_component.set(ID_name, declarator.get_base_name()); new_component.set(ID_pretty_name, declarator.get_base_name()); new_component.type()=declaration.full_type(declarator); typecheck_type(new_component.type()); if(!is_complete_type(new_component.type()) && (new_component.type().id()!=ID_array || !to_array_type(new_component.type()).is_incomplete())) { error().source_location=new_component.type().source_location(); error() << "incomplete type not permitted here" << eom; throw 0; } components.push_back(new_component); } } } unsigned anon_member_counter=0; // scan for anonymous members, and name them for(auto &member : components) { if(member.get_name()!=irep_idt()) continue; member.set_name("$anon"+std::to_string(anon_member_counter++)); member.set_anonymous(true); } // scan for duplicate members { std::unordered_set<irep_idt, irep_id_hash> members; for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(!members.insert(it->get_name()).second) { error().source_location=it->source_location(); error() << "duplicate member '" << it->get_name() << '\'' << eom; throw 0; } } } // We allow an incomplete (C99) array as _last_ member! // Zero-length is allowed everywhere. if(type.id()==ID_struct || type.id()==ID_union) { for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { typet &c_type=it->type(); if(c_type.id()==ID_array && to_array_type(c_type).is_incomplete()) { // needs to be last member if(type.id()==ID_struct && it!=--components.end()) { error().source_location=it->source_location(); error() << "flexible struct member must be last member" << eom; throw 0; } // make it zero-length c_type.id(ID_array); c_type.set(ID_size, from_integer(0, index_type())); } } } // We may add some minimal padding inside and at // the end of structs and // as additional member for unions. if(type.id()==ID_struct) add_padding(to_struct_type(type), *this); else if(type.id()==ID_union) add_padding(to_union_type(type), *this); // Now remove zero-width bit-fields, these are just // for adjusting alignment. for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // blank { if(it->type().id()==ID_c_bit_field && to_c_bit_field_type(it->type()).get_width()==0) it=components.erase(it); else it++; } // finally, check _Static_assert inside the compound for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // no it++ { if(it->id()==ID_static_assert) { assert(it->operands().size()==2); exprt &assertion=it->op0(); typecheck_expr(assertion); typecheck_expr(it->op1()); assertion.make_typecast(bool_typet()); make_constant(assertion); if(assertion.is_false()) { error().source_location=it->source_location(); error() << "failed _Static_assert" << eom; throw 0; } else if(!assertion.is_true()) { // should warn/complain } it=components.erase(it); } else it++; } }
void c_typecheck_baset::typecheck_c_enum_type(typet &type) { // These come with the declarations // of the enum constants as operands. exprt &as_expr=static_cast<exprt &>(static_cast<irept &>(type)); source_locationt source_location=type.source_location(); // We allow empty enums in the grammar to get better // error messages. if(as_expr.operands().empty()) { error().source_location=source_location; error() << "empty enum" << eom; throw 0; } // enums start at zero; // we also track min and max to find a nice base type mp_integer value=0, min_value=0, max_value=0; std::list<c_enum_typet::c_enum_membert> enum_members; // We need to determine a width, and a signedness // to obtain an 'underlying type'. // We just do int, but gcc might pick smaller widths // if the type is marked as 'packed'. // gcc/clang may also pick a larger width. Visual Studio doesn't. for(auto &op : as_expr.operands()) { ansi_c_declarationt &declaration=to_ansi_c_declaration(op); exprt &v=declaration.declarator().value(); if(v.is_not_nil()) // value given? { exprt tmp_v=v; typecheck_expr(tmp_v); add_rounding_mode(tmp_v); simplify(tmp_v, *this); if(tmp_v.is_true()) value=1; else if(tmp_v.is_false()) value=0; else if(!to_integer(tmp_v, value)) { } else { error().source_location=v.source_location(); error() << "enum is not a constant"; throw 0; } } if(value<min_value) min_value=value; if(value>max_value) max_value=value; typet constant_type= enum_constant_type(min_value, max_value); v=from_integer(value, constant_type); declaration.type()=constant_type; typecheck_declaration(declaration); irep_idt base_name= declaration.declarator().get_base_name(); irep_idt identifier= declaration.declarator().get_name(); // store c_enum_typet::c_enum_membert member; member.set_identifier(identifier); member.set_base_name(base_name); member.set_value(integer2string(value)); enum_members.push_back(member); // produce value for next constant ++value; } // Remove these now; we add them to the // c_enum symbol later. as_expr.operands().clear(); bool is_packed=type.get_bool(ID_C_packed); // tag? if(type.find(ID_tag).is_nil()) { // None, it's anonymous. We generate a tag. std::string anon_identifier="#anon_enum"; for(const auto &member : enum_members) { anon_identifier+='$'; anon_identifier+=id2string(member.get_base_name()); anon_identifier+='='; anon_identifier+=id2string(member.get_value()); } if(is_packed) anon_identifier+="#packed"; type.add(ID_tag).set(ID_identifier, anon_identifier); } irept &tag=type.add(ID_tag); irep_idt base_name=tag.get(ID_C_base_name); irep_idt identifier=tag.get(ID_identifier); // Put into symbol table symbolt enum_tag_symbol; enum_tag_symbol.is_type=true; enum_tag_symbol.type=type; enum_tag_symbol.location=source_location; enum_tag_symbol.is_file_local=true; enum_tag_symbol.base_name=base_name; enum_tag_symbol.name=identifier; // throw in the enum members as 'body' irept::subt &body=enum_tag_symbol.type.add(ID_body).get_sub(); for(const auto &member : enum_members) body.push_back(member); // We use a subtype to store the underlying type. typet underlying_type= enum_underlying_type(min_value, max_value, is_packed); enum_tag_symbol.type.subtype()=underlying_type; // is it in the symbol table already? symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); if(s_it!=symbol_table.symbols.end()) { // Yes. symbolt &symbol=s_it->second; if(symbol.type.id()==ID_incomplete_c_enum) { // Ok, overwrite the type in the symbol table. // This gives us the members and the subtype. symbol.type=enum_tag_symbol.type; } else if(symbol.type.id()==ID_c_enum) { // We might already have the same anonymous enum, and this is // simply ok. Note that the C standard treats these as // different types. if(!base_name.empty()) { error().source_location=type.source_location(); error() << "redeclaration of enum tag" << eom; throw 0; } } else { error().source_location=source_location; error() << "use of tag that does not match previous declaration" << eom; throw 0; } } else { symbolt *new_symbol; move_symbol(enum_tag_symbol, new_symbol); } // We produce a c_enum_tag as the resulting type. type.id(ID_c_enum_tag); type.remove(ID_tag); type.set(ID_identifier, identifier); }