symbolt &cpp_declarator_convertert::convert_new_symbol( const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator) { irep_idt pretty_name=get_pretty_name(); symbolt symbol; symbol.name=final_identifier; symbol.base_name=base_name; symbol.value=declarator.value(); symbol.location=declarator.name().source_location(); symbol.mode=linkage_spec==ID_auto?ID_cpp:linkage_spec; symbol.module=cpp_typecheck.module; symbol.type=final_type; symbol.is_type=is_typedef; symbol.is_macro=is_typedef && !is_template_parameter; symbol.pretty_name=pretty_name; // Constant? These are propagated. if(symbol.type.get_bool(ID_C_constant) && symbol.value.is_not_nil()) symbol.is_macro=true; if(member_spec.is_inline()) symbol.type.set(ID_C_inlined, true); if(!symbol.is_type) { if(is_code) { // it is a function if(storage_spec.is_static()) symbol.is_file_local=true; } else { // it is a variable symbol.is_state_var=true; symbol.is_lvalue = !is_reference(symbol.type) && !(symbol.type.get_bool(ID_C_constant) && is_number(symbol.type) && symbol.value.id() == ID_constant); if(cpp_typecheck.cpp_scopes.current_scope().is_global_scope()) { symbol.is_static_lifetime=true; if(storage_spec.is_extern()) symbol.is_extern=true; } else { if(storage_spec.is_static()) { symbol.is_static_lifetime=true; symbol.is_file_local=true; } else if(storage_spec.is_extern()) { cpp_typecheck.err_location(storage_spec); throw "external storage not permitted here"; } } } } if(symbol.is_static_lifetime) cpp_typecheck.dynamic_initializations.push_back(symbol.name); // move early, it must be visible before doing any value symbolt *new_symbol; if(cpp_typecheck.symbol_table.move(symbol, new_symbol)) throw "cpp_typecheckt::convert_declarator: symbol_table.move() failed"; if(!is_code) { cpp_scopest::id_sett id_set; cpp_typecheck.cpp_scopes.current_scope().lookup( base_name, cpp_scopet::SCOPE_ONLY, id_set); for(cpp_scopest::id_sett::const_iterator id_it=id_set.begin(); id_it!=id_set.end(); id_it++) { const cpp_idt &id=**id_it; // the name is already in the scope // this is ok if they belong to different categories if(!id.is_class() && !id.is_enum()) { cpp_typecheck.err_location(new_symbol->location); cpp_typecheck.str << "`" << base_name << "' already in scope"; throw 0; } } } // put into scope cpp_idt &identifier= cpp_typecheck.cpp_scopes.put_into_scope(*new_symbol, *scope, is_friend); if(is_template) identifier.id_class=cpp_idt::TEMPLATE; else if(is_template_parameter) identifier.id_class=cpp_idt::TEMPLATE_PARAMETER; else if(is_typedef) identifier.id_class=cpp_idt::TYPEDEF; else identifier.id_class=cpp_idt::SYMBOL; // do the value if(!new_symbol->is_type) { if(is_code && declarator.type().id()!=ID_template) cpp_typecheck.add_function_body(new_symbol); if(!is_code) cpp_typecheck.convert_initializer(*new_symbol); } enforce_rules(*new_symbol); return *new_symbol; }
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; } }
symbolt &cpp_declarator_convertert::convert_new_symbol( const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator) { irep_idt pretty_name=get_pretty_name(); symbolt symbol; symbol.name=final_identifier; symbol.base_name=base_name; symbol.value=declarator.value(); symbol.location=declarator.name().location(); symbol.mode=mode; symbol.module=cpp_typecheck.module; symbol.type=final_type; symbol.is_type=is_typedef; symbol.is_macro=is_typedef && !is_template_argument; symbol.pretty_name=pretty_name; symbol.mode=cpp_typecheck.current_mode; // We always insert throw_decl to the begin of the function if(declarator.throw_decl().statement()=="throw_decl") { symbol.value.operands().insert( symbol.value.operands().begin(), declarator.throw_decl()); // Insert flag to end of constructor // so we know when to remove throw_decl symbol.value.operands().push_back( codet("throw_decl_end")); } // Constant? These are propagated. if(symbol.type.cmt_constant() && symbol.value.is_not_nil()) symbol.is_macro=true; if(member_spec.is_inline()) symbol.type.set("#inlined", true); if(!symbol.is_type) { if(!is_code) { // it is a variable symbol.is_statevar=true; symbol.lvalue = !is_reference(symbol.type) && !(symbol.type.cmt_constant() && is_number(symbol.type) && symbol.value.id() == "constant"); if(cpp_typecheck.cpp_scopes.current_scope().is_global_scope()) { symbol.static_lifetime=true; if(storage_spec.is_extern()) symbol.is_extern=true; } else { if(storage_spec.is_static()) { //symbol.static_lifetime=true; symbol.file_local=true; } else if(storage_spec.is_extern()) { cpp_typecheck.err_location(storage_spec); throw "external storage not permitted here"; } } } } if(symbol.static_lifetime) cpp_typecheck.dinis.push_back(symbol.name); // move early, it must be visible before doing any value symbolt *new_symbol; if(cpp_typecheck.context.move(symbol, new_symbol)) throw "cpp_typecheckt::convert_declarator: context.move() failed"; if(!is_code) { cpp_scopest::id_sett id_set; cpp_typecheck.cpp_scopes.current_scope().lookup( base_name, cpp_scopet::SYMBOL, id_set); for(cpp_scopest::id_sett::const_iterator id_it=id_set.begin(); id_it!=id_set.end(); id_it++) { const cpp_idt &id=**id_it; // the name is already in the scope // this is ok if they belong to different categories if(!id.is_class() && !id.is_enum()) { cpp_typecheck.err_location(new_symbol->location); cpp_typecheck.str << "`" << base_name << "' already in scope"; throw 0; } } } // put into scope cpp_idt &identifier= cpp_typecheck.cpp_scopes.put_into_scope(*new_symbol, *scope, is_friend); if(is_template) identifier.id_class=cpp_idt::TEMPLATE; else if(is_template_argument) identifier.id_class=cpp_idt::TEMPLATE_ARGUMENT; else if(is_typedef) identifier.id_class=cpp_idt::TYPEDEF; else identifier.id_class=cpp_idt::SYMBOL; // do the value if(!new_symbol->is_type) { if(is_code && declarator.type().id()!="template") cpp_typecheck.add_function_body(new_symbol); if(!is_code && !declarator.find("name").get_bool("catch_decl")) cpp_typecheck.convert_initializer(*new_symbol); } enforce_rules(*new_symbol); return *new_symbol; }