void ansi_c_typecheckt::typecheck() { for(ansi_c_parse_treet::itemst::iterator it=parse_tree.items.begin(); it!=parse_tree.items.end(); it++) { typecheck_declaration(*it); } }
void c_typecheck_baset::typecheck_decl(codet &code) { // this comes with 1 operand, which is a declaration if(code.operands().size()!=1) { err_location(code); error() << "decl expected to have 1 operand" << eom; throw 0; } // op0 must be declaration if(code.op0().id()!=ID_declaration) { err_location(code); error() << "decl statement expected to have declaration as operand" << eom; throw 0; } ansi_c_declarationt declaration; declaration.swap(code.op0()); if(declaration.get_is_static_assert()) { assert(declaration.operands().size()==2); codet new_code(ID_static_assert); new_code.add_source_location()=code.source_location(); new_code.operands().swap(declaration.operands()); code.swap(new_code); typecheck_code(code); return; // done } typecheck_declaration(declaration); std::list<codet> new_code; // iterate over declarators for(ansi_c_declarationt::declaratorst::const_iterator d_it=declaration.declarators().begin(); d_it!=declaration.declarators().end(); d_it++) { irep_idt identifier=d_it->get_name(); // look it up symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) { err_location(code); error() << "failed to find decl symbol `" << identifier << "' in symbol table" << eom; throw 0; } symbolt &symbol=s_it->second; // This must not be an incomplete type, unless it's 'extern' // or a typedef. if(!symbol.is_type && !symbol.is_extern && !is_complete_type(symbol.type)) { error().source_location=symbol.location; error() << "incomplete type not permitted here" << eom; throw 0; } // see if it's a typedef // or a function // or static if(symbol.is_type || symbol.type.id()==ID_code || symbol.is_static_lifetime) { // we ignore } else { code_declt code; code.add_source_location()=symbol.location; code.symbol()=symbol.symbol_expr(); code.symbol().add_source_location()=symbol.location; // add initializer, if any if(symbol.value.is_not_nil()) { code.operands().resize(2); code.op1()=symbol.value; } new_code.push_back(code); } } // stash away any side-effects in the declaration new_code.splice(new_code.begin(), clean_code); if(new_code.empty()) { source_locationt source_location=code.source_location(); code=code_skipt(); code.add_source_location()=source_location; } else if(new_code.size()==1) { code.swap(new_code.front()); } else { // build a decl-block code_blockt code_block(new_code); code_block.set_statement(ID_decl_block); code.swap(code_block); } }
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); }