bool remove_function_pointerst::is_type_compatible( 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(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 arguments const code_typet::argumentst &call_arguments=call_type.arguments(); const code_typet::argumentst &function_arguments=function_type.arguments(); if(function_type.has_ellipsis() && function_arguments.empty()) { // always ok } else if(call_type.has_ellipsis() && call_arguments.empty()) { // always ok } else { // we are quite strict here, could be much more generous if(call_arguments.size()!=function_arguments.size()) return false; for(unsigned i=0; i<call_arguments.size(); i++) if(!arg_is_type_compatible(call_arguments[i].type(), function_arguments[i].type())) return false; } return true; }
void cpp_typecheckt::convert_arguments( const irep_idt &mode, code_typet &function_type) { code_typet::argumentst &arguments= function_type.arguments(); for(code_typet::argumentst::iterator it=arguments.begin(); it!=arguments.end(); it++) convert_argument(mode, *it); }
void goto_inlinet::parameter_assignments( const locationt &location, const code_typet &code_type, const exprt::operandst &arguments, goto_programt &dest) { // iterates over the operands exprt::operandst::const_iterator it1=arguments.begin(); goto_programt::local_variablest local_variables; const code_typet::argumentst &argument_types= code_type.arguments(); // iterates over the types of the arguments for(code_typet::argumentst::const_iterator it2=argument_types.begin(); it2!=argument_types.end(); it2++) { // if you run out of actual arguments there was a mismatch if(it1==arguments.end()) { err_location(location); throw "function call: not enough arguments"; } const exprt &argument=static_cast<const exprt &>(*it2); // this is the type the n-th argument should be const typet &arg_type=ns.follow(argument.type()); const irep_idt &identifier=argument.cmt_identifier(); if(identifier=="") { err_location(location); throw "no identifier for function argument"; } { const symbolt &symbol=ns.lookup(identifier); goto_programt::targett decl=dest.add_instruction(); decl->make_other(); exprt tmp = code_declt(symbol_expr(symbol)); migrate_expr(tmp, decl->code); decl->location=location; decl->function=location.get_function(); decl->local_variables=local_variables; } local_variables.insert(identifier); // nil means "don't assign" if(it1->is_nil()) { } else { // this is the actual parameter exprt actual(*it1); // it should be the same exact type type2tc arg_type_2, actual_type_2; migrate_type(arg_type, arg_type_2); migrate_type(actual.type(), actual_type_2); if (!base_type_eq(arg_type_2, actual_type_2, ns)) { const typet &f_argtype = ns.follow(arg_type); const typet &f_acttype = ns.follow(actual.type()); // we are willing to do some conversion if((f_argtype.id()=="pointer" && f_acttype.id()=="pointer") || (f_argtype.is_array() && f_acttype.id()=="pointer" && f_argtype.subtype()==f_acttype.subtype())) { actual.make_typecast(arg_type); } else if((f_argtype.id()=="signedbv" || f_argtype.id()=="unsignedbv" || f_argtype.is_bool()) && (f_acttype.id()=="signedbv" || f_acttype.id()=="unsignedbv" || f_acttype.is_bool())) { actual.make_typecast(arg_type); } else { err_location(location); str << "function call: argument `" << identifier << "' type mismatch: got " << from_type(ns, identifier, it1->type()) << ", expected " << from_type(ns, identifier, arg_type); throw 0; } } // adds an assignment of the actual parameter to the formal parameter code_assignt assignment(symbol_exprt(identifier, arg_type), actual); assignment.location()=location; dest.add_instruction(ASSIGN); dest.instructions.back().location=location; migrate_expr(assignment, dest.instructions.back().code); dest.instructions.back().local_variables=local_variables; dest.instructions.back().function=location.get_function(); } 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::argumentst &arguments=code_type.arguments(); if(arguments.size()>ops.size()) { // Check for default values. ops.reserve(arguments.size()); for(unsigned i=ops.size(); i<arguments.size(); i++) { const exprt &default_value= arguments[i].default_value(); if(default_value.is_nil()) return false; ops.push_back(default_value); } } else if(arguments.size()<ops.size()) { // check for ellipsis if(!code_type.has_ellipsis()) return false; } for(unsigned 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>=arguments.size()) { // Ellipsis is the 'worst' of the conversion sequences distance+=1000; continue; } exprt argument=arguments[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 && argument.get("#base_name")==ID_this) { argument.type().set("#reference", true); argument.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(argument.type()) << std::endl; #endif // can we do the standard conversion sequence? if(cpp_typecheck.implicit_conversion_sequence( operand, argument.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; }