void cpp_typecheckt::typecheck_class_template( cpp_declarationt &declaration) { // Do template parameters. This also sets up the template scope. cpp_scopet &template_scope= typecheck_template_parameters(declaration.template_type()); typet &type=declaration.type(); template_typet &template_type=declaration.template_type(); bool has_body=type.find(ID_body).is_not_nil(); const cpp_namet &cpp_name= static_cast<const cpp_namet &>(type.find(ID_tag)); if(cpp_name.is_nil()) { err_location(type.source_location()); throw "class templates must not be anonymous"; } if(!cpp_name.is_simple_name()) { err_location(cpp_name.source_location()); throw "simple name expected as class template tag"; } irep_idt base_name=cpp_name.get_base_name(); const cpp_template_args_non_tct &partial_specialization_args= declaration.partial_specialization_args(); const irep_idt symbol_name= class_template_identifier( base_name, template_type, partial_specialization_args); #if 0 // Check if the name is already used by a different template // in the same scope. { cpp_scopet::id_sett id_set; cpp_scopes.current_scope().lookup( base_name, cpp_scopet::SCOPE_ONLY, cpp_scopet::TEMPLATE, id_set); if(!id_set.empty()) { const symbolt &previous=lookup((*id_set.begin())->identifier); if(previous.name!=symbol_name || id_set.size()>1) { err_location(cpp_name.source_location()); str << "template declaration of `" << base_name.c_str() << " does not match previous declaration\n"; str << "location of previous definition: " << previous.location; throw 0; } } } #endif // check if we have it already symbol_tablet::symbolst::iterator previous_symbol= symbol_table.symbols.find(symbol_name); if(previous_symbol!=symbol_table.symbols.end()) { // there already cpp_declarationt &previous_declaration= to_cpp_declaration(previous_symbol->second.type); bool previous_has_body= previous_declaration.type().find(ID_body).is_not_nil(); // check if we have 2 bodies if(has_body && previous_has_body) { err_location(cpp_name.source_location()); str << "template struct `" << base_name << "' defined previously" << std::endl; str << "location of previous definition: " << previous_symbol->second.location; throw 0; } if(has_body) { // We replace the template! // We have to retain any default parameters from the previous declaration. salvage_default_arguments( previous_declaration.template_type(), declaration.template_type()); previous_symbol->second.type.swap(declaration); #if 0 std::cout << "*****\n"; std::cout << *cpp_scopes.id_map[symbol_name]; std::cout << "*****\n"; std::cout << "II: " << symbol_name << std::endl; #endif // We also replace the template scope (the old one could be deleted). cpp_scopes.id_map[symbol_name]=&template_scope; // We also fix the parent scope in order to see the new // template arguments } else { // just update any default arguments salvage_default_arguments( declaration.template_type(), previous_declaration.template_type()); } assert(cpp_scopes.id_map[symbol_name]->id_class == cpp_idt::TEMPLATE_SCOPE); return; } // it's not there yet symbolt symbol; symbol.name=symbol_name; symbol.base_name=base_name; symbol.location=cpp_name.source_location(); symbol.mode=ID_cpp; symbol.module=module; symbol.type.swap(declaration); symbol.is_macro=false; symbol.value=exprt("template_decls"); symbol.pretty_name= cpp_scopes.current_scope().prefix+id2string(symbol.base_name); symbolt *new_symbol; if(symbol_table.move(symbol, new_symbol)) throw "cpp_typecheckt::typecheck_compound_type: symbol_table.move() failed"; // put into current scope cpp_idt &id=cpp_scopes.put_into_scope(*new_symbol); id.id_class=cpp_idt::TEMPLATE; id.prefix=cpp_scopes.current_scope().prefix+ id2string(new_symbol->base_name); // link the template symbol with the template scope cpp_scopes.id_map[symbol_name]=&template_scope; assert(cpp_scopes.id_map[symbol_name]->id_class==cpp_idt::TEMPLATE_SCOPE); }
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); } }