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::convert_anonymous_union( cpp_declarationt &declaration, codet &code) { codet new_code(ID_decl_block); new_code.reserve_operands(declaration.declarators().size()); // unnamed object std::string identifier="#anon_union"+i2string(anon_counter++); irept name(ID_name); name.set(ID_identifier, identifier); name.set(ID_C_source_location, declaration.source_location()); cpp_namet cpp_name; cpp_name.move_to_sub(name); cpp_declaratort declarator; declarator.name()=cpp_name; cpp_declarator_convertert cpp_declarator_converter(*this); const symbolt &symbol= cpp_declarator_converter.convert(declaration, declarator); if(!cpp_is_pod(declaration.type())) { error().source_location=follow(declaration.type()).source_location(); error() << "anonymous union is not POD" << eom; throw 0; } codet decl_statement(ID_decl); decl_statement.reserve_operands(2); decl_statement.copy_to_operands(cpp_symbol_expr(symbol)); new_code.move_to_operands(decl_statement); // do scoping symbolt union_symbol=symbol_table.symbols[follow(symbol.type).get(ID_name)]; const irept::subt &components=union_symbol.type.add(ID_components).get_sub(); forall_irep(it, components) { if(it->find(ID_type).id()==ID_code) { error().source_location=union_symbol.type.source_location(); error() << "anonymous union `" << union_symbol.base_name << "' shall not have function members" << eom; throw 0; } const irep_idt &base_name=it->get(ID_base_name); if(cpp_scopes.current_scope().contains(base_name)) { error().source_location=union_symbol.type.source_location(); error() << "identifier `" << base_name << "' already in scope" << eom; throw 0; } cpp_idt &id=cpp_scopes.current_scope().insert(base_name); id.id_class = cpp_idt::SYMBOL; id.identifier=it->get(ID_name); id.class_identifier=union_symbol.name; id.is_member=true; } symbol_table.symbols[union_symbol.name].type.set( "#unnamed_object", symbol.base_name); code.swap(new_code); }
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); } }