void cpp_typecheckt::convert_function(symbolt &symbol) { code_typet &function_type= to_code_type(template_subtype(symbol.type)); // only a prototype? if(symbol.value.is_nil()) return; // if it is a destructor, add the implicit code if(symbol.type.get(ID_return_type)==ID_destructor) { const symbolt &msymb=lookup(symbol.type.get(ID_C_member_name)); assert(symbol.value.id()==ID_code); assert(symbol.value.get(ID_statement)==ID_block); symbol.value.copy_to_operands(dtor(msymb)); } // enter appropriate scope cpp_save_scopet saved_scope(cpp_scopes); cpp_scopet &function_scope=cpp_scopes.set_scope(symbol.name); // fix the scope's prefix function_scope.prefix+=id2string(symbol.name)+"::"; // genuine function definition -- do the parameter declarations convert_arguments(symbol.mode, function_type); // create "this" if it's a non-static method if(function_scope.is_method && !function_scope.is_static_member) { code_typet::argumentst &arguments=function_type.arguments(); assert(arguments.size()>=1); code_typet::argumentt &this_argument_expr=arguments.front(); function_scope.this_expr=exprt(ID_symbol, this_argument_expr.type()); function_scope.this_expr.set(ID_identifier, this_argument_expr.get(ID_C_identifier)); } else function_scope.this_expr.make_nil(); // do the function body start_typecheck_code(); // save current return type typet old_return_type=return_type; return_type=function_type.return_type(); // constructor, destructor? if(return_type.id()==ID_constructor || return_type.id()==ID_destructor) return_type=empty_typet(); typecheck_code(to_code(symbol.value)); symbol.value.type()=symbol.type; return_type = old_return_type; }
void cpp_typecheckt::convert_template_function_or_member_specialization( cpp_declarationt &declaration) { cpp_save_scopet saved_scope(cpp_scopes); if(declaration.declarators().size()!=1 || declaration.declarators().front().type().id()!=ID_function_type) { err_location(declaration.type()); str << "expected function template specialization"; throw 0; } assert(declaration.declarators().size()==1); cpp_declaratort declarator=declaration.declarators().front(); cpp_namet &cpp_name=declarator.name(); if(cpp_name.is_qualified()) { err_location(cpp_name.source_location()); str << "qualifiers not expected here"; throw 0; } // There is specialization (instantiation with template arguments) // but also function overloading (no template arguments) assert(!cpp_name.get_sub().empty()); if(cpp_name.get_sub().back().id()==ID_template_args) { // proper specialization with arguments if(cpp_name.get_sub().size()!=2 || cpp_name.get_sub()[0].id()!=ID_name || cpp_name.get_sub()[1].id()!=ID_template_args) { // currently we are more restrictive // than the standard err_location(cpp_name.source_location()); str << "bad template-function-specialization name"; throw 0; } std::string base_name= cpp_name.get_sub()[0].get(ID_identifier).c_str(); cpp_scopest::id_sett id_set; cpp_scopes.current_scope().lookup( base_name, cpp_scopet::SCOPE_ONLY, id_set); if(id_set.empty()) { err_location(cpp_name.source_location()); str << "template function `" << base_name << "' not found"; throw 0; } else if(id_set.size()>1) { err_location(cpp_name.source_location()); str << "template function `" << base_name << "' is ambiguous"; } const symbolt &template_symbol= lookup((*id_set.begin())->identifier); cpp_template_args_tct template_args= typecheck_template_args( declaration.source_location(), template_symbol, to_cpp_template_args_non_tc(cpp_name.get_sub()[1])); cpp_name.get_sub().pop_back(); typet specialization; specialization.swap(declarator); instantiate_template( cpp_name.source_location(), template_symbol, template_args, template_args, specialization); } else { // Just overloading, but this is still a template // for disambiguation purposes! // http://www.gotw.ca/publications/mill17.htm cpp_declarationt new_declaration=declaration; new_declaration.remove(ID_template_type); new_declaration.remove(ID_is_template); new_declaration.set(ID_C_template, ""); // todo, get identifier convert_non_template_declaration(new_declaration); } }
void cpp_typecheckt::typecheck_friend_declaration( symbolt &symbol, cpp_declarationt &declaration) { // A friend of a class can be a function/method, // or a struct/class/union type. if(declaration.is_template()) { return; // TODO err_location(declaration.type().location()); str << "friend template not supported"; throw 0; } // we distinguish these whether there is a declarator if(declaration.declarators().empty()) { typet &ftype=declaration.type(); // must be struct or union if(ftype.id()!=ID_struct && ftype.id()!=ID_union) { err_location(declaration.type()); str << "unexpected friend"; throw 0; } if(ftype.find(ID_body).is_not_nil()) { err_location(declaration.type()); str << "friend declaration must not have compound body"; throw 0; } // typecheck ftype // TODO // typecheck_type(ftype); // assert(ftype.id()==ID_symbol); // symbol.type.add("#friends").move_to_sub(ftype); return; } // It should be a friend function. // Do the declarators. Forall_cpp_declarators(sub_it, declaration) { bool has_value = sub_it->value().is_not_nil(); if(!has_value) { // If no value is found, then we jump to the // global scope, and we convert the declarator // as if it were declared there cpp_save_scopet saved_scope(cpp_scopes); cpp_scopes.go_to_global_scope(); cpp_declarator_convertert cpp_declarator_converter(*this); const symbolt &conv_symb = cpp_declarator_converter.convert( declaration.type(), declaration.storage_spec(), declaration.member_spec(), *sub_it); exprt symb_expr = cpp_symbol_expr(conv_symb); symbol.type.add("#friends").move_to_sub(symb_expr); } else { cpp_declarator_convertert cpp_declarator_converter(*this); cpp_declarator_converter.is_friend = true; declaration.member_spec().set_inline(true); const symbolt &conv_symb = cpp_declarator_converter.convert( declaration.type(), declaration.storage_spec(), declaration.member_spec(), *sub_it); exprt symb_expr = cpp_symbol_expr(conv_symb); symbol.type.add("#friends").move_to_sub(symb_expr); } }
void cpp_typecheckt::convert_class_template_specialization( cpp_declarationt &declaration) { cpp_save_scopet saved_scope(cpp_scopes); typet &type=declaration.type(); assert(type.id()==ID_struct); cpp_namet &cpp_name= static_cast<cpp_namet &>(type.add(ID_tag)); if(cpp_name.is_qualified()) { err_location(cpp_name.source_location()); str << "qualifiers not expected here"; throw 0; } if(cpp_name.get_sub().size()!=2 || cpp_name.get_sub()[0].id()!=ID_name || cpp_name.get_sub()[1].id()!=ID_template_args) { // currently we are more restrictive // than the standard err_location(cpp_name.source_location()); str << "bad template-class-sepcialization name"; throw 0; } irep_idt base_name= cpp_name.get_sub()[0].get(ID_identifier); // copy the template arguments const cpp_template_args_non_tct template_args_non_tc= to_cpp_template_args_non_tc(cpp_name.get_sub()[1]); // Remove the template arguments from the name. cpp_name.get_sub().pop_back(); // get the template symbol cpp_scopest::id_sett id_set; cpp_scopes.current_scope().lookup( base_name, cpp_scopet::SCOPE_ONLY, cpp_idt::TEMPLATE, id_set); // remove any specializations for(cpp_scopest::id_sett::iterator it=id_set.begin(); it!=id_set.end(); ) // no it++ { cpp_scopest::id_sett::iterator next=it; next++; if(lookup((*it)->identifier).type. find("specialization_of").is_not_nil()) id_set.erase(it); it=next; } // only one should be left if(id_set.empty()) { err_location(type.source_location()); str << "class template `" << base_name << "' not found"; throw 0; } else if(id_set.size()>1) { err_location(type); str << "class template `" << base_name << "' is ambiguous"; throw 0; } symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find((*id_set.begin())->identifier); assert(s_it!=symbol_table.symbols.end()); symbolt &template_symbol=s_it->second; if(!template_symbol.type.get_bool(ID_is_template)) { err_location(type); str << "expected a template"; } #if 0 // is this partial specialization? if(declaration.template_type().parameters().empty()) { // typecheck arguments -- these are for the 'primary' template! cpp_template_args_tct template_args_tc= typecheck_template_args( declaration.source_location(), to_cpp_declaration(template_symbol.type).template_type(), template_args_non_tc); // Full specialization, i.e., template<>. // We instantiate. instantiate_template( cpp_name.source_location(), template_symbol, template_args_tc, type); } else #endif { // partial specialization -- we typecheck declaration.partial_specialization_args()=template_args_non_tc; declaration.set_specialization_of(template_symbol.name); typecheck_class_template(declaration); } }
void cpp_typecheckt::convert(cpp_namespace_spect &namespace_spec) { // save the scope cpp_save_scopet saved_scope(cpp_scopes); const irep_idt &name=namespace_spec.get_namespace(); if(name=="") { // "unique namespace" err_location(namespace_spec); throw "unique namespace not supported yet"; } irep_idt final_name(name); std::string identifier= cpp_identifier_prefix(current_mode)+"::"+ cpp_scopes.current_scope().prefix+id2string(final_name); contextt::symbolst::const_iterator it= context.symbols.find(identifier); if(it!=context.symbols.end()) { if(namespace_spec.alias().is_not_nil()) { err_location(namespace_spec); str << "namespace alias `" << final_name << "' previously declared" << std::endl; str << "location of previous declaration: " << it->second.location; throw 0; } if(it->second.type.id()!="namespace") { err_location(namespace_spec); str << "namespace `" << final_name << "' previously declared" << std::endl; str << "location of previous declaration: " << it->second.location; throw 0; } // enter that scope cpp_scopes.set_scope(it->first); } else { symbolt symbol; symbol.name=identifier; symbol.base_name=final_name; symbol.value.make_nil(); symbol.location=namespace_spec.location(); symbol.mode=current_mode; symbol.module=module; symbol.type=typet("namespace"); if(context.move(symbol)) throw "cpp_typecheckt::convert_namespace: context.move() failed"; cpp_scopes.new_namespace(final_name); } /*if(namespace_spec.alias().is_not_nil()) { cpp_typecheck_resolvet resolver(*this); cpp_scopet &s=resolver.resolve_namespace(namespace_spec.alias()); cpp_scopes.current_scope().add_using_scope(s); } else {*/ // do the declarations for(cpp_namespace_spect::itemst::iterator it=namespace_spec.items().begin(); it!=namespace_spec.items().end(); it++) convert(*it); // } }