bool remove_function_pointerst::is_type_compatible( bool return_value_used, const code_typet &call_type, const code_typet &function_type) { // we are willing to ignore anything that's returned // if we call with 'void' if(!return_value_used) { } else if(type_eq(call_type.return_type(), empty_typet(), ns)) { // ok } else { if(!arg_is_type_compatible(call_type.return_type(), function_type.return_type())) return false; } // let's look at the parameters const code_typet::parameterst &call_parameters=call_type.parameters(); const code_typet::parameterst &function_parameters=function_type.parameters(); if(function_type.has_ellipsis() && function_parameters.empty()) { // always ok } else if(call_type.has_ellipsis() && call_parameters.empty()) { // always ok } else { // we are quite strict here, could be much more generous if(call_parameters.size()!=function_parameters.size()) return false; for(unsigned i=0; i<call_parameters.size(); i++) if(!arg_is_type_compatible(call_parameters[i].type(), function_parameters[i].type())) return false; } return true; }
void goto_inlinet::parameter_destruction( const source_locationt &source_location, const irep_idt &function_name, const code_typet &code_type, goto_programt &dest) { const code_typet::parameterst ¶meter_types= code_type.parameters(); // iterates over the types of the parameters for(code_typet::parameterst::const_iterator it=parameter_types.begin(); it!=parameter_types.end(); it++) { const code_typet::parametert ¶meter=*it; const irep_idt &identifier=parameter.get_identifier(); if(identifier==irep_idt()) { error().source_location=source_location; error() << "no identifier for function parameter" << eom; throw 0; } { const symbolt &symbol=ns.lookup(identifier); goto_programt::targett dead=dest.add_instruction(); dead->make_dead(); dead->code=code_deadt(symbol.symbol_expr()); dead->code.add_source_location()=source_location; dead->source_location=source_location; dead->function=function_name; } } }
void c_typecheck_baset::typecheck_code_type(code_typet &type) { // the return type is still 'subtype()' type.return_type()=type.subtype(); type.remove_subtype(); code_typet::parameterst ¶meters=type.parameters(); // if we don't have any parameters, we assume it's (...) if(parameters.empty()) { type.make_ellipsis(); } else // we do have parameters { // is the last one ellipsis? if(type.parameters().back().id()==ID_ellipsis) { type.make_ellipsis(); type.parameters().pop_back(); } parameter_map.clear(); for(auto ¶m : type.parameters()) { // turn the declarations into parameters if(param.id()==ID_declaration) { ansi_c_declarationt &declaration= to_ansi_c_declaration(param); code_typet::parametert parameter; // first fix type typet &type=parameter.type(); type=declaration.full_type(declaration.declarator()); std::list<codet> tmp_clean_code; tmp_clean_code.swap(clean_code); // ignore side-effects typecheck_type(type); tmp_clean_code.swap(clean_code); adjust_function_parameter(type); // adjust the identifier irep_idt identifier=declaration.declarator().get_name(); // abstract or not? if(identifier==irep_idt()) { // abstract parameter.add_source_location()=declaration.type().source_location(); } else { // make visible now, later parameters might use it parameter_map[identifier]=type; parameter.set_base_name(declaration.declarator().get_base_name()); parameter.add_source_location()= declaration.declarator().source_location(); } // put the parameter in place of the declaration param.swap(parameter); } } parameter_map.clear(); if(parameters.size()==1 && follow(parameters[0].type()).id()==ID_empty) { // if we just have one parameter of type void, remove it parameters.clear(); } } typecheck_type(type.return_type()); // 6.7.6.3: // "A function declarator shall not specify a return type that // is a function type or an array type." const typet &return_type=follow(type.return_type()); if(return_type.id()==ID_array) { error().source_location=type.source_location(); error() << "function must not return array" << eom; throw 0; } if(return_type.id()==ID_code) { error().source_location=type.source_location(); error() << "function must not return function type" << eom; throw 0; } }
void c_typecheck_baset::typecheck_code_type(code_typet &type) { code_typet::parameterst ¶meters=type.parameters(); // if we don't have any parameters, we assume it's (...) if(parameters.empty()) { type.make_ellipsis(); } else { // we do have parameters parameter_map.clear(); for(unsigned i=0; i<type.parameters().size(); i++) { code_typet::parametert ¶meter=type.parameters()[i]; // first fix type typet &type=parameter.type(); typecheck_type(type); adjust_function_parameter(type); // adjust the identifier irep_idt identifier=parameter.get_identifier(); if(identifier!=irep_idt()) { identifier=add_language_prefix(identifier); id_replace_mapt::const_iterator m_it=id_replace_map.find(identifier); if(m_it!=id_replace_map.end()) identifier=m_it->second; parameter.set_identifier(identifier); // make visible now, later parameters might use it parameter_map[identifier]=type; } } parameter_map.clear(); if(parameters.size()==1 && follow(parameters[0].type()).id()==ID_empty) { // if we just have one parameter of type void, remove it parameters.clear(); } } typecheck_type(type.return_type()); // 6.7.6.3: // "A function declarator shall not specify a return type that // is a function type or an array type." const typet &return_type=follow(type.return_type()); if(return_type.id()==ID_array) { err_location(type); throw "function must not return array"; } if(return_type.id()==ID_code) { err_location(type); throw "function must not return function type"; } }
void goto_inlinet::parameter_assignments( const source_locationt &source_location, const irep_idt &function_name, const code_typet &code_type, const exprt::operandst &arguments, goto_programt &dest) { // iterates over the operands exprt::operandst::const_iterator it1=arguments.begin(); const code_typet::parameterst ¶meter_types= code_type.parameters(); // iterates over the types of the parameters for(code_typet::parameterst::const_iterator it2=parameter_types.begin(); it2!=parameter_types.end(); it2++) { const code_typet::parametert ¶meter=*it2; // this is the type the n-th argument should be const typet &par_type=ns.follow(parameter.type()); const irep_idt &identifier=parameter.get_identifier(); if(identifier==irep_idt()) { error().source_location=source_location; error() << "no identifier for function parameter" << eom; throw 0; } { const symbolt &symbol=ns.lookup(identifier); goto_programt::targett decl=dest.add_instruction(); decl->make_decl(); decl->code=code_declt(symbol.symbol_expr()); decl->code.add_source_location()=source_location; decl->source_location=source_location; decl->function=function_name; } // this is the actual parameter exprt actual; // if you run out of actual arguments there was a mismatch if(it1==arguments.end()) { warning().source_location=source_location; warning() << "call to `" << function_name << "': " << "not enough arguments, " << "inserting non-deterministic value" << eom; actual=side_effect_expr_nondett(par_type); } else actual=*it1; // nil means "don't assign" if(actual.is_nil()) { } else { // it should be the same exact type as the parameter, // subject to some exceptions if(!base_type_eq(par_type, actual.type(), ns)) { const typet &f_partype = ns.follow(par_type); const typet &f_acttype = ns.follow(actual.type()); // we are willing to do some conversion if((f_partype.id()==ID_pointer && f_acttype.id()==ID_pointer) || (f_partype.id()==ID_pointer && f_acttype.id()==ID_array && f_partype.subtype()==f_acttype.subtype())) { actual.make_typecast(par_type); } else if((f_partype.id()==ID_signedbv || f_partype.id()==ID_unsignedbv || f_partype.id()==ID_bool) && (f_acttype.id()==ID_signedbv || f_acttype.id()==ID_unsignedbv || f_acttype.id()==ID_bool)) { actual.make_typecast(par_type); } else { error().source_location=actual.find_source_location(); error() << "function call: argument `" << identifier << "' type mismatch: argument is `" // << from_type(ns, identifier, actual.type()) << actual.type().pretty() << "', parameter is `" << from_type(ns, identifier, par_type) << "'" << eom; throw 0; } } // adds an assignment of the actual parameter to the formal parameter code_assignt assignment(symbol_exprt(identifier, par_type), actual); assignment.add_source_location()=source_location; dest.add_instruction(ASSIGN); dest.instructions.back().source_location=source_location; dest.instructions.back().code.swap(assignment); dest.instructions.back().function=function_name; } if(it1!=arguments.end()) ++it1; } if(it1!=arguments.end()) { // too many arguments -- we just ignore that, no harm done } }
bool cpp_typecheck_fargst::match( const code_typet &code_type, unsigned &distance, cpp_typecheckt &cpp_typecheck) const { distance=0; exprt::operandst ops = operands; const code_typet::parameterst ¶meters=code_type.parameters(); if(parameters.size()>ops.size()) { // Check for default values. ops.reserve(parameters.size()); for(std::size_t i=ops.size(); i<parameters.size(); i++) { const exprt &default_value= parameters[i].default_value(); if(default_value.is_nil()) return false; ops.push_back(default_value); } } else if(parameters.size()<ops.size()) { // check for ellipsis if(!code_type.has_ellipsis()) return false; } for(std::size_t i=0; i<ops.size(); i++) { // read // http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/implicit_conversion_sequences.htm // // The following are the three categories of conversion sequences in order from best to worst: // * Standard conversion sequences // * User-defined conversion sequences // * Ellipsis conversion sequences if(i>=parameters.size()) { // Ellipsis is the 'worst' of the conversion sequences distance+=1000; continue; } exprt parameter=parameters[i]; exprt &operand=ops[i]; #if 0 // unclear, todo if(is_reference(operand.type())) std::cout << "O: " << operand.pretty() << std::endl; assert(!is_reference(operand.type())); #endif // "this" is a special case -- we turn the pointer type // into a reference type to do the type matching if(i==0 && parameter.get(ID_C_base_name)==ID_this) { parameter.type().set(ID_C_reference, true); parameter.type().set("#this", true); } unsigned rank = 0; exprt new_expr; #if 0 std::cout << "C: " << cpp_typecheck.to_string(operand.type()) << " -> " << cpp_typecheck.to_string(parameter.type()) << std::endl; #endif // can we do the standard conversion sequence? if(cpp_typecheck.implicit_conversion_sequence( operand, parameter.type(), new_expr, rank)) { // ok distance+=rank; #if 0 std::cout << "OK " << rank << std::endl; #endif } else { #if 0 std::cout << "NOT OK" << std::endl; #endif return false; // no conversion possible } } return true; }