See More

/*******************************************************************\ Module: C++ Language Type Checking Author: Daniel Kroening, [email protected] \********************************************************************/ /// \file /// C++ Language Type Checking #include #include #include "cpp_declarator_converter.h" #include "cpp_typecheck.h" #include "cpp_util.h" void cpp_typecheckt::convert(cpp_declarationt &declaration) { // see if the declaration is empty if(declaration.is_empty()) return; // The function bodies must not be checked here, // but only at the very end when all declarations have been // processed (or considering forward declarations at least) // templates are done in a dedicated function if(declaration.is_template()) convert_template_declaration(declaration); else convert_non_template_declaration(declaration); } codet cpp_typecheckt::convert_anonymous_union(cpp_declarationt &declaration) { codet new_code(ID_decl_block); new_code.reserve_operands(declaration.declarators().size()); // unnamed object std::string identifier="#anon_union"+std::to_string(anon_counter++); const cpp_namet cpp_name(identifier, declaration.source_location()); 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())) { const typet &followed = declaration.type().id() == ID_struct_tag ? static_cast( follow_tag(to_struct_tag_type(declaration.type()))) : declaration.type().id() == ID_union_tag ? static_cast( follow_tag(to_union_tag_type(declaration.type()))) : declaration.type().id() == ID_c_enum_tag ? static_cast( follow_tag(to_c_enum_tag_type(declaration.type()))) : declaration.type(); error().source_location = followed.source_location(); error() << "anonymous union is not POD" << eom; throw 0; } new_code.add_to_operands(code_frontend_declt(cpp_symbol_expr(symbol))); // do scoping symbolt &union_symbol = symbol_table.get_writeable_ref( follow_tag(to_union_tag_type(symbol.type)).get(ID_name)); for(const auto &c : to_union_type(union_symbol.type).components()) { if(c.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 = c.get_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::id_classt::SYMBOL; id.identifier = c.get_name(); id.class_identifier=union_symbol.name; id.is_member=true; } union_symbol.type.set(ID_C_unnamed_object, symbol.base_name); return new_code; } void cpp_typecheckt::convert_non_template_declaration( cpp_declarationt &declaration) { PRECONDITION(!declaration.is_template()); // we first check if this is a typedef typet &declaration_type=declaration.type(); bool is_typedef=declaration.is_typedef(); // the name anonymous tag types declaration.name_anon_struct_union(); // do the type of the declaration if(declaration.declarators().empty() || !has_auto(declaration_type)) 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); // mark as 'already typechecked' if(!declaration.declarators().empty()) already_typechecked_typet::make_already_typechecked(declaration_type); // Special treatment for anonymous unions if( declaration.declarators().empty() && ((declaration.type().id() == ID_struct_tag && follow_tag(to_struct_tag_type(declaration.type())) .get_bool(ID_C_is_anonymous)) || (declaration.type().id() == ID_union_tag && follow_tag(to_union_tag_type(declaration.type())) .get_bool(ID_C_is_anonymous)) || declaration.type().get_bool(ID_C_is_anonymous))) { if(declaration.type().id() != ID_union_tag) { error().source_location = declaration.type().source_location(); error() << "top-level declaration does not declare anything" << eom; throw 0; } convert_anonymous_union(declaration); } // do the declarators (optional) for(auto &d : declaration.declarators()) { // copy the declarator (we destroy the original) cpp_declaratort declarator=d; 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); if(!symbol.is_type && !symbol.is_extern && symbol.type.id() == ID_empty) { error().source_location = symbol.location; error() << "void-typed symbol not permitted" << eom; throw 0; } // 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); d.swap(tmp); // is there a constructor to be called for the declarator? if(symbol.is_lvalue && declarator.init_args().has_operands()) { auto constructor = cpp_constructor( symbol.location, cpp_symbol_expr(symbol), declarator.init_args().operands()); if(constructor.has_value()) symbol.value = constructor.value(); else symbol.value = nil_exprt(); } } }