void cpp_typecheckt::convert(cpp_declarationt &declaration) { // see if the declaration is empty if(declaration.find(ID_type).is_nil() && !declaration.has_operands()) return; // Record the function bodies so we can check them later. // This function is used recursively, so we save them. function_bodiest old_function_bodies=function_bodies; function_bodies.clear(); // templates are done in a dedicated function if(declaration.is_template()) convert_template_declaration(declaration); else convert_non_template_declaration(declaration); typecheck_function_bodies(); function_bodies=old_function_bodies; }
void cpp_typecheckt::convert_non_template_declaration( cpp_declarationt &declaration) { assert(!declaration.is_template()); // we first check if this is a typedef typet &declaration_type=declaration.type(); bool is_typedef=declaration.is_typedef(); declaration.name_anon_struct_union(); typecheck_type(declaration_type); // Elaborate any class template instance _unless_ we do a typedef. // These are only elaborated on usage! if(!is_typedef) elaborate_class_template(declaration_type); // Special treatment for anonymous unions if(declaration.declarators().empty() && follow(declaration.type()).get_bool(ID_C_is_anonymous)) { typet final_type=follow(declaration.type()); if(final_type.id()!=ID_union) { error().source_location=final_type.source_location(); error() << "top-level declaration does not declare anything" << eom; throw 0; } codet dummy; convert_anonymous_union(declaration, dummy); } // do the declarators (optional) Forall_cpp_declarators(it, declaration) { // copy the declarator (we destroy the original) cpp_declaratort declarator=*it; cpp_declarator_convertert cpp_declarator_converter(*this); cpp_declarator_converter.is_typedef=is_typedef; symbolt &symbol=cpp_declarator_converter.convert( declaration_type, declaration.storage_spec(), declaration.member_spec(), declarator); // any template instance to remember? if(declaration.find(ID_C_template).is_not_nil()) { symbol.type.set(ID_C_template, declaration.find(ID_C_template)); symbol.type.set(ID_C_template_arguments, declaration.find(ID_C_template_arguments)); } // replace declarator by symbol expression exprt tmp=cpp_symbol_expr(symbol); it->swap(tmp); // is there a constructor to be called for the declarator? if(symbol.is_lvalue && declarator.init_args().has_operands()) { symbol.value= cpp_constructor( symbol.location, cpp_symbol_expr(symbol), declarator.init_args().operands()); } }
void cpp_typecheckt::convert_template_declaration( cpp_declarationt &declaration) { assert(declaration.is_template()); if(declaration.member_spec().is_virtual()) { err_location(declaration); str << "invalid use of 'virtual' in template declaration"; throw 0; } if(declaration.is_typedef()) { err_location(declaration); str << "template declaration for typedef"; throw 0; } typet &type=declaration.type(); // there are // 1) function templates // 2) class templates // 3) template members of class templates (static or methods) // 4) variable templates (C++14) if(declaration.is_class_template()) { // there should not be declarators if(!declaration.declarators().empty()) { err_location(declaration); throw "class template not expected to have declarators"; } // it needs to be a class template if(type.id()!=ID_struct) { err_location(declaration); throw "expected class template"; } // Is it class template specialization? // We can tell if there are template arguments in the class name, // like template<...> class tag<stuff> ... if((static_cast<const cpp_namet &>( type.find(ID_tag))).has_template_args()) { convert_class_template_specialization(declaration); return; } typecheck_class_template(declaration); return; } else // maybe function template, maybe class template member, maye template variable { // there should be declarators in either case if(declaration.declarators().empty()) { err_location(declaration); throw "non-class template is expected to have a declarator"; } // Is it function template specialization? // Only full specialization is allowed! if(declaration.template_type().template_parameters().empty()) { convert_template_function_or_member_specialization(declaration); return; } // Explicit qualification is forbidden for function templates, // which we can use to distinguish them. assert(declaration.declarators().size()>=1); cpp_declaratort &declarator=declaration.declarators()[0]; const cpp_namet &cpp_name=to_cpp_name(declarator.add(ID_name)); if(cpp_name.is_qualified() || cpp_name.has_template_args()) return typecheck_class_template_member(declaration); // must be function template typecheck_function_template(declaration); return; } }
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); } }