void cpp_typecheckt::typecheck_enum_type(typet &type) { // first save qualifiers c_qualifierst qualifiers; qualifiers.read(type); // these behave like special struct types // replace by type symbol cpp_enum_typet &enum_type=to_cpp_enum_type(type); bool anonymous=!enum_type.has_tag(); irep_idt base_name; if(anonymous) { // we fabricate a tag based on the enum constants contained base_name=enum_type.generate_anon_tag(); } else { const cpp_namet &tag=enum_type.tag(); if(tag.is_simple_name()) base_name=tag.get_base_name(); else { err_location(type); throw "enum tag is expected to be a simple name"; } } bool has_body=enum_type.has_body(); bool tag_only_declaration=enum_type.get_tag_only_declaration(); cpp_scopet &dest_scope= tag_scope(base_name, has_body, tag_only_declaration); const irep_idt symbol_name= dest_scope.prefix+"tag."+id2string(base_name); // check if we have it symbol_tablet::symbolst::iterator previous_symbol= symbol_table.symbols.find(symbol_name); if(previous_symbol!=symbol_table.symbols.end()) { // we do! symbolt &symbol=previous_symbol->second; if(has_body) { err_location(type); str << "error: enum symbol `" << base_name << "' declared previously" << std::endl; str << "location of previous definition: " << symbol.location << std::endl; throw 0; } } else if(has_body) { std::string pretty_name= cpp_scopes.current_scope().prefix+id2string(base_name); symbolt symbol; symbol.name=symbol_name; symbol.base_name=base_name; symbol.value.make_nil(); symbol.location=type.location(); symbol.mode=ID_cpp; symbol.module=module; symbol.type.swap(type); symbol.is_type=true; symbol.is_macro=false; symbol.pretty_name=pretty_name; // move early, must be visible before doing body symbolt *new_symbol; if(symbol_table.move(symbol, new_symbol)) throw "cpp_typecheckt::typecheck_enum_type: symbol_table.move() failed"; // put into scope cpp_idt &scope_identifier= cpp_scopes.put_into_scope(*new_symbol, dest_scope); scope_identifier.id_class=cpp_idt::CLASS; typecheck_enum_body(*new_symbol); } else { err_location(type); str << "use of enum `" << base_name << "' without previous declaration"; throw 0; } // create type symbol type=typet(ID_symbol); type.set(ID_identifier, symbol_name); qualifiers.write(type); }
void cpp_typecheckt::typecheck_enum_type(typet &type) { // first save qualifiers c_qualifierst qualifiers; qualifiers.read(type); cpp_enum_typet &enum_type=to_cpp_enum_type(type); bool anonymous=!enum_type.has_tag(); irep_idt base_name; if(anonymous) { // we fabricate a tag based on the enum constants contained base_name=enum_type.generate_anon_tag(); } else { const cpp_namet &tag=enum_type.tag(); if(tag.is_simple_name()) base_name=tag.get_base_name(); else { err_location(type); throw "enum tag is expected to be a simple name"; } } bool has_body=enum_type.has_body(); bool tag_only_declaration=enum_type.get_tag_only_declaration(); cpp_scopet &dest_scope= tag_scope(base_name, has_body, tag_only_declaration); const irep_idt symbol_name= dest_scope.prefix+"tag-"+id2string(base_name); // check if we have it symbol_tablet::symbolst::iterator previous_symbol= symbol_table.symbols.find(symbol_name); if(previous_symbol!=symbol_table.symbols.end()) { // we do! symbolt &symbol=previous_symbol->second; if(has_body) { err_location(type); str << "error: enum symbol `" << base_name << "' declared previously\n"; str << "location of previous definition: " << symbol.location; throw 0; } } else if(has_body) { std::string pretty_name= cpp_scopes.current_scope().prefix+id2string(base_name); // C++11 enumerations have an underlying type, // which defaults to int. // enums without underlying type may be 'packed'. if(type.subtype().is_nil()) type.subtype()=signed_int_type(); else { typecheck_type(type.subtype()); if(type.subtype().id()==ID_signedbv || type.subtype().id()==ID_unsignedbv) { } else { err_location(type); str << "underlying type must be integral"; throw 0; } } symbolt symbol; symbol.name=symbol_name; symbol.base_name=base_name; symbol.value.make_nil(); symbol.location=type.source_location(); symbol.mode=ID_cpp; symbol.module=module; symbol.type.swap(type); symbol.is_type=true; symbol.is_macro=false; symbol.pretty_name=pretty_name; // move early, must be visible before doing body symbolt *new_symbol; if(symbol_table.move(symbol, new_symbol)) throw "cpp_typecheckt::typecheck_enum_type: symbol_table.move() failed"; // put into scope cpp_idt &scope_identifier= cpp_scopes.put_into_scope(*new_symbol, dest_scope); scope_identifier.id_class=cpp_idt::CLASS; typecheck_enum_body(*new_symbol); } else { err_location(type); str << "use of enum `" << base_name << "' without previous declaration"; throw 0; } // create enum tag expression, and add the qualifiers type=c_enum_tag_typet(symbol_name); qualifiers.write(type); }
void cpp_typecheckt::typecheck_compound_type( struct_union_typet &type) { // first save qualifiers c_qualifierst qualifiers(type); // now clear them from the type type.remove(ID_C_constant); type.remove(ID_C_volatile); type.remove(ID_C_restricted); // get the tag name bool anonymous=type.find(ID_tag).is_nil(); irep_idt base_name; cpp_scopet *dest_scope=NULL; bool has_body=type.find(ID_body).is_not_nil(); bool tag_only_declaration=type.get_bool(ID_C_tag_only_declaration); if(anonymous) { base_name="#anon_"+type.id_string()+i2string(anon_counter++); type.set("#is_anonymous", true); // anonymous structs always go into the current scope dest_scope=&cpp_scopes.current_scope(); } else { const cpp_namet &cpp_name= to_cpp_name(type.find(ID_tag)); // scope given? if(cpp_name.is_simple_name()) { base_name=cpp_name.get_base_name(); dest_scope=&tag_scope(base_name, has_body, tag_only_declaration); } else { cpp_save_scopet cpp_save_scope(cpp_scopes); cpp_typecheck_resolvet cpp_typecheck_resolve(*this); cpp_template_args_non_tct t_args; dest_scope=&cpp_typecheck_resolve.resolve_scope(cpp_name, base_name, t_args); } } const irep_idt symbol_name= language_prefix+ dest_scope->prefix+ "tag."+id2string(base_name); // check if we have it already contextt::symbolst::iterator previous_symbol= context.symbols.find(symbol_name); if(previous_symbol!=context.symbols.end()) { // we do! symbolt &symbol=previous_symbol->second; if(has_body) { if(symbol.type.id()=="incomplete_"+type.id_string()) { // a previously incomplete struct/union becomes complete symbol.type.swap(type); typecheck_compound_body(symbol); } else { err_location(type.location()); str << "error: struct symbol `" << base_name << "' declared previously" << std::endl; str << "location of previous definition: " << symbol.location; throw 0; } } } else { // produce new symbol symbolt symbol; symbol.name=symbol_name; symbol.base_name=base_name; symbol.value.make_nil(); symbol.location=type.location(); symbol.mode=ID_cpp; symbol.module=module; symbol.type.swap(type); symbol.is_type=true; symbol.is_macro=false; symbol.pretty_name=cpp_scopes.current_scope().prefix+id2string(symbol.base_name); symbol.type.set(ID_tag, symbol.pretty_name); // move early, must be visible before doing body symbolt *new_symbol; if(context.move(symbol, new_symbol)) throw "cpp_typecheckt::typecheck_compound_type: context.move() failed"; // put into dest_scope cpp_idt &id=cpp_scopes.put_into_scope(*new_symbol, *dest_scope); id.id_class=cpp_idt::CLASS; id.is_scope=true; id.prefix=cpp_scopes.current_scope().prefix+ id2string(new_symbol->base_name)+"::"; id.class_identifier=new_symbol->name; id.id_class=cpp_idt::CLASS; if(has_body) typecheck_compound_body(*new_symbol); else { typet new_type("incomplete_"+new_symbol->type.id_string()); new_type.set(ID_tag, new_symbol->base_name); new_symbol->type.swap(new_type); } } // create type symbol typet symbol_type(ID_symbol); symbol_type.set(ID_identifier, symbol_name); qualifiers.write(symbol_type); type.swap(symbol_type); }