void cpp_typecheckt::convert(cpp_usingt &cpp_using) { // there are two forms of using clauses: // a) using namespace SCOPE; ("using directive") // b) using SCOPE::id; ("using declaration") cpp_typecheck_resolvet resolver(*this); cpp_save_scopet save_scope(this->cpp_scopes); irep_idt base_name; cpp_template_args_non_tct template_args; resolver.resolve_scope(cpp_using.name(), base_name, template_args); bool qualified=cpp_using.name().is_qualified(); cpp_scopest::id_sett id_set; cpp_scopes.current_scope().lookup( base_name, qualified?cpp_scopet::QUALIFIED:cpp_scopet::RECURSIVE, id_set); bool using_directive=cpp_using.get_namespace(); if(id_set.empty()) { error().source_location=cpp_using.name().source_location(); error() << "using " << (using_directive?"namespace":"identifier") << " `" << base_name << "' not found" << eom; throw 0; } // go back to where we used to be save_scope.restore(); for(cpp_scopest::id_sett::iterator it=id_set.begin(); it!=id_set.end(); it++) { if(using_directive) { if((*it)->id_class==cpp_idt::NAMESPACE) cpp_scopes.current_scope().add_using_scope(static_cast<cpp_scopet &>(**it)); else { // we should likely complain about this } } else // declaration { // we copy all 'normal' identifiers into the current scope if((*it)->id_class!=cpp_idt::TEMPLATE_PARAMETER && (*it)->id_class!=cpp_idt::NAMESPACE) cpp_scopes.current_scope().insert(**it); } } }
symbolt &cpp_declarator_convertert::convert( const typet &declaration_type, const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator) { assert(declaration_type.is_not_nil()); if(declaration_type.id()=="cpp-cast-operator") { typet type; type.swap(declarator.name().get_sub().back()); declarator.type().subtype()=type; std::string tmp; cpp_typecheck.typecheck_type(type); irept name(ID_name); name.set(ID_identifier, "("+cpp_type2name(type)+")"); declarator.name().get_sub().back().swap(name); } assert(declarator.id()==ID_cpp_declarator); final_type=declarator.merge_type(declaration_type); assert(final_type.is_not_nil()); cpp_template_args_non_tct template_args; // run resolver on scope { cpp_save_scopet save_scope(cpp_typecheck.cpp_scopes); cpp_typecheck_resolvet cpp_typecheck_resolve(cpp_typecheck); cpp_typecheck_resolve.resolve_scope( declarator.name(), base_name, template_args); scope=&cpp_typecheck.cpp_scopes.current_scope(); // check the declarator-part of the type, in that scope cpp_typecheck.typecheck_type(final_type); } is_code=is_code_type(final_type); // global-scope arrays must have fixed size if(scope->is_global_scope()) cpp_typecheck.check_fixed_size_array(final_type); get_final_identifier(); // first see if it is a member if(scope->id_class==cpp_idt::CLASS && !is_friend) { // it's a member! it must be declared already typet &method_qualifier= static_cast<typet &>(declarator.method_qualifier()); // adjust template type if(final_type.id()==ID_template) { assert(0); typet tmp; tmp.swap(final_type.subtype()); final_type.swap(tmp); } // try static first symbol_tablet::symbolst::iterator c_it= cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) { // adjust type if it's a non-static member function if(final_type.id()==ID_code) cpp_typecheck.adjust_method_type( scope->identifier, final_type, method_qualifier); get_final_identifier(); // try again c_it=cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) { cpp_typecheck.err_location(declarator.name()); cpp_typecheck.str << "member `" << base_name << "' not found in scope `" << scope->identifier << "'"; throw 0; } } assert(c_it!=cpp_typecheck.symbol_table.symbols.end()); symbolt &symbol=c_it->second; combine_types(declarator.name().source_location(), final_type, symbol); enforce_rules(symbol); // If it is a constructor, we take care of the // object initialization if(final_type.get(ID_return_type)==ID_constructor) { const cpp_namet &name=declarator.name(); exprt symbol_expr= cpp_typecheck.resolve( name, cpp_typecheck_resolvet::TYPE, cpp_typecheck_fargst()); if(symbol_expr.id()!=ID_type || symbol_expr.type().id()!=ID_symbol) { cpp_typecheck.err_location(name.source_location()); cpp_typecheck.str << "error: expected type"; throw 0; } irep_idt identifier=symbol_expr.type().get(ID_identifier); const symbolt &symb=cpp_typecheck.lookup(identifier); const typet &type = symb.type; assert(type.id()==ID_struct); if(declarator.find(ID_member_initializers).is_nil()) declarator.set(ID_member_initializers, ID_member_initializers); cpp_typecheck.check_member_initializers( type.find(ID_bases), to_struct_type(type).components(), declarator.member_initializers()); cpp_typecheck.full_member_initialization( to_struct_type(type), declarator.member_initializers()); } if(!storage_spec.is_extern()) symbol.is_extern=false; // initializer? handle_initializer(symbol, declarator); return symbol; } else { // no, it's no way a method // we won't allow the constructor/destructor type if(final_type.id()==ID_code && to_code_type(final_type).return_type().id()==ID_constructor) { cpp_typecheck.err_location(declarator.name().source_location()); cpp_typecheck.str << "function must have return type"; throw 0; } // already there? symbol_tablet::symbolst::iterator c_it= cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) return convert_new_symbol(storage_spec, member_spec, declarator); symbolt &symbol=c_it->second; if(!storage_spec.is_extern()) symbol.is_extern = false; if(declarator.get_bool("#template_case")) return symbol; combine_types(declarator.name().source_location(), final_type, symbol); enforce_rules(symbol); // initializer? handle_initializer(symbol, declarator); if(symbol.type.id()=="cpp-template-type") { cpp_scopet::id_sett id_set; scope->lookup_identifier(symbol.name, cpp_idt::TEMPLATE_PARAMETER, id_set); if(id_set.empty()) { cpp_idt &identifier= cpp_typecheck.cpp_scopes.put_into_scope(symbol,*scope); identifier.id_class=cpp_idt::TEMPLATE_PARAMETER; } } return symbol; } }
codet cpp_typecheckt::cpp_constructor( const source_locationt &source_location, const exprt &object, const exprt::operandst &operands) { exprt object_tc=object; typecheck_expr(object_tc); elaborate_class_template(object_tc.type()); typet tmp_type(object_tc.type()); follow_symbol(tmp_type); assert(!is_reference(tmp_type)); if(tmp_type.id()==ID_array) { // We allow only one operand and it must be tagged with '#array_ini'. // Note that the operand is an array that is used for copy-initialization. // In the general case, a program is not allow to use this form of // construct. This way of initializing an array is used internaly only. // The purpose of the tag #arra_ini is to rule out ill-formed // programs. if(!operands.empty() && !operands.front().get_bool("#array_ini")) { error().source_location=source_location; error() << "bad array initializer" << eom; throw 0; } assert(operands.empty() || operands.size()==1); if(operands.empty() && cpp_is_pod(tmp_type)) { codet nil; nil.make_nil(); return nil; } const exprt &size_expr= to_array_type(tmp_type).size(); if(size_expr.id()=="infinity") { // don't initialize codet nil; nil.make_nil(); return nil; } exprt tmp_size=size_expr; make_constant_index(tmp_size); mp_integer s; if(to_integer(tmp_size, s)) { error().source_location=source_location; error() << "array size `" << to_string(size_expr) << "' is not a constant" << eom; throw 0; } /*if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt op_tc=operands.front(); typecheck_expr(op_tc); // Override constantness object_tc.type().set("#constant", false); object_tc.set("#lvalue", true); side_effect_exprt assign("assign"); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, op_tc); typecheck_side_effect_assignment(assign); new_code.expression()=assign; return new_code; } else*/ { codet new_code(ID_block); // for each element of the array, call the default constructor for(mp_integer i=0; i < s; ++i) { exprt::operandst tmp_operands; exprt constant=from_integer(i, index_type()); constant.add_source_location()=source_location; exprt index(ID_index); index.copy_to_operands(object); index.copy_to_operands(constant); index.add_source_location()=source_location; if(!operands.empty()) { exprt operand(ID_index); operand.copy_to_operands(operands.front()); operand.copy_to_operands(constant); operand.add_source_location()=source_location; tmp_operands.push_back(operand); } exprt i_code = cpp_constructor(source_location, index, tmp_operands); if(i_code.is_nil()) { new_code.is_nil(); break; } new_code.move_to_operands(i_code); } return new_code; } } else if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } if(operands_tc.empty()) { // a POD is NOT initialized new_code.make_nil(); } else if(operands_tc.size()==1) { // Override constantness object_tc.type().set(ID_C_constant, false); object_tc.set(ID_C_lvalue, true); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, operands_tc.front()); typecheck_side_effect_assignment(assign); new_code.expression()=assign; } else { error().source_location=source_location; error() << "initialization of POD requires one argument, " "but got " << operands.size() << eom; throw 0; } return new_code; } else if(tmp_type.id()==ID_union) { assert(0); // Todo: union } else if(tmp_type.id()==ID_struct) { exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } const struct_typet &struct_type= to_struct_type(tmp_type); // set most-derived bits codet block(ID_block); for(std::size_t i=0; i < struct_type.components().size(); i++) { const irept &component=struct_type.components()[i]; if(component.get(ID_base_name)!="@most_derived") continue; exprt member(ID_member, bool_typet()); member.set(ID_component_name, component.get(ID_name)); member.copy_to_operands(object_tc); member.add_source_location()=source_location; member.set(ID_C_lvalue, object_tc.get_bool(ID_C_lvalue)); exprt val=false_exprt(); if(!component.get_bool("from_base")) val=true_exprt(); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.move_to_operands(member, val); typecheck_side_effect_assignment(assign); code_expressiont code_exp; code_exp.expression()=assign; block.move_to_operands(code_exp); } // enter struct scope cpp_save_scopet save_scope(cpp_scopes); cpp_scopes.set_scope(struct_type.get(ID_name)); // find name of constructor const struct_typet::componentst &components= struct_type.components(); irep_idt constructor_name; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &type=it->type(); if(!it->get_bool(ID_from_base) && type.id()==ID_code && type.find(ID_return_type).id()==ID_constructor) { constructor_name=it->get(ID_base_name); break; } } // there is always a constructor for non-PODs assert(constructor_name!=""); irept cpp_name(ID_cpp_name); cpp_name.get_sub().push_back(irept(ID_name)); cpp_name.get_sub().back().set(ID_identifier, constructor_name); cpp_name.get_sub().back().set(ID_C_source_location, source_location); side_effect_expr_function_callt function_call; function_call.add_source_location()=source_location; function_call.function().swap(static_cast<exprt&>(cpp_name)); function_call.arguments().reserve(operands_tc.size()); for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) function_call.op1().copy_to_operands(*it); typecheck_side_effect_function_call(function_call); assert(function_call.get(ID_statement)==ID_temporary_object); exprt &initializer = static_cast<exprt &>(function_call.add(ID_initializer)); assert(initializer.id()==ID_code && initializer.get(ID_statement)==ID_expression); side_effect_expr_function_callt &func_ini= to_side_effect_expr_function_call(initializer.op0()); exprt &tmp_this=func_ini.arguments().front(); assert(tmp_this.id()==ID_address_of && tmp_this.op0().id()=="new_object"); exprt address_of(ID_address_of, typet(ID_pointer)); address_of.type().subtype()=object_tc.type(); address_of.copy_to_operands(object_tc); tmp_this.swap(address_of); if(block.operands().empty()) return to_code(initializer); else { block.move_to_operands(initializer); return block; } } else assert(false); codet nil; nil.make_nil(); return nil; }