symbolt &cpp_declarator_convertert::convert( const typet &declaration_type, const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator) { assert(declaration_type.is_not_nil()); if(declaration_type.id()=="cpp-cast-operator") { typet type; type.swap(declarator.name().get_sub().back()); declarator.type().subtype()=type; std::string tmp; cpp_typecheck.typecheck_type(type); irept name(ID_name); name.set(ID_identifier, "("+cpp_type2name(type)+")"); declarator.name().get_sub().back().swap(name); } assert(declarator.id()==ID_cpp_declarator); final_type=declarator.merge_type(declaration_type); assert(final_type.is_not_nil()); cpp_template_args_non_tct template_args; // run resolver on scope { cpp_save_scopet save_scope(cpp_typecheck.cpp_scopes); cpp_typecheck_resolvet cpp_typecheck_resolve(cpp_typecheck); cpp_typecheck_resolve.resolve_scope( declarator.name(), base_name, template_args); scope=&cpp_typecheck.cpp_scopes.current_scope(); // check the declarator-part of the type, in that scope cpp_typecheck.typecheck_type(final_type); } is_code=is_code_type(final_type); // global-scope arrays must have fixed size if(scope->is_global_scope()) cpp_typecheck.check_fixed_size_array(final_type); get_final_identifier(); // first see if it is a member if(scope->id_class==cpp_idt::CLASS && !is_friend) { // it's a member! it must be declared already typet &method_qualifier= static_cast<typet &>(declarator.method_qualifier()); // adjust template type if(final_type.id()==ID_template) { assert(0); typet tmp; tmp.swap(final_type.subtype()); final_type.swap(tmp); } // try static first symbol_tablet::symbolst::iterator c_it= cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) { // adjust type if it's a non-static member function if(final_type.id()==ID_code) cpp_typecheck.adjust_method_type( scope->identifier, final_type, method_qualifier); get_final_identifier(); // try again c_it=cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) { cpp_typecheck.err_location(declarator.name()); cpp_typecheck.str << "member `" << base_name << "' not found in scope `" << scope->identifier << "'"; throw 0; } } assert(c_it!=cpp_typecheck.symbol_table.symbols.end()); symbolt &symbol=c_it->second; combine_types(declarator.name().source_location(), final_type, symbol); enforce_rules(symbol); // If it is a constructor, we take care of the // object initialization if(final_type.get(ID_return_type)==ID_constructor) { const cpp_namet &name=declarator.name(); exprt symbol_expr= cpp_typecheck.resolve( name, cpp_typecheck_resolvet::TYPE, cpp_typecheck_fargst()); if(symbol_expr.id()!=ID_type || symbol_expr.type().id()!=ID_symbol) { cpp_typecheck.err_location(name.source_location()); cpp_typecheck.str << "error: expected type"; throw 0; } irep_idt identifier=symbol_expr.type().get(ID_identifier); const symbolt &symb=cpp_typecheck.lookup(identifier); const typet &type = symb.type; assert(type.id()==ID_struct); if(declarator.find(ID_member_initializers).is_nil()) declarator.set(ID_member_initializers, ID_member_initializers); cpp_typecheck.check_member_initializers( type.find(ID_bases), to_struct_type(type).components(), declarator.member_initializers()); cpp_typecheck.full_member_initialization( to_struct_type(type), declarator.member_initializers()); } if(!storage_spec.is_extern()) symbol.is_extern=false; // initializer? handle_initializer(symbol, declarator); return symbol; } else { // no, it's no way a method // we won't allow the constructor/destructor type if(final_type.id()==ID_code && to_code_type(final_type).return_type().id()==ID_constructor) { cpp_typecheck.err_location(declarator.name().source_location()); cpp_typecheck.str << "function must have return type"; throw 0; } // already there? symbol_tablet::symbolst::iterator c_it= cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) return convert_new_symbol(storage_spec, member_spec, declarator); symbolt &symbol=c_it->second; if(!storage_spec.is_extern()) symbol.is_extern = false; if(declarator.get_bool("#template_case")) return symbol; combine_types(declarator.name().source_location(), final_type, symbol); enforce_rules(symbol); // initializer? handle_initializer(symbol, declarator); if(symbol.type.id()=="cpp-template-type") { cpp_scopet::id_sett id_set; scope->lookup_identifier(symbol.name, cpp_idt::TEMPLATE_PARAMETER, id_set); if(id_set.empty()) { cpp_idt &identifier= cpp_typecheck.cpp_scopes.put_into_scope(symbol,*scope); identifier.id_class=cpp_idt::TEMPLATE_PARAMETER; } } return symbol; } }
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); }