int match_endpoints(endp p1, endp p2, endp amatch) { /* Should this be type_equal ? unclear (only real diff, given that we will forbid old style parameter lists, is transparent union handling) */ if (type_compatible(endpoint_type(p1), endpoint_type(p2))) { if (amatch) *amatch = *p2; return 1; } else return 0; }
std::shared_ptr<Instantiation<Impl>> Module_scanner<Impl>::create_instantiation(ast::Module_instantiation const& node) { std::shared_ptr<Instantiation<Impl>> inst(new Instantiation<Impl>); std::string module_name; inst->name = dynamic_cast<ast::Identifier const&>(node.instance_name()).identifier(); if( m_mod.instantiations.count(inst->name) > 0 ) throw std::runtime_error(std::string("Instantiation with name ") + inst->name + std::string(" already exists")); if( node.is_template_instantiation() ) { LOG4CXX_TRACE(Namespace_scanner<Impl>::m_logger, "instantiating module template"); // extract name auto tmpl_id = node.template_identifier(); std::vector<Label> qname = tmpl_id.name(); std::string qname_join = boost::algorithm::join(qname, "::"); // find template std::shared_ptr<Module_template<Impl>> tmpl; if( qname.size() > 1 ) { tmpl = find_by_path(m_mod, &Module<Impl>::module_templates, qname); } else { tmpl = find_module_template(m_mod, qname[0]); } if( !tmpl ) { std::stringstream strm; strm << "Can not find module template with name '" << qname_join << "'"; throw std::runtime_error(strm.str()); } // determine module name and type overrides module_name = qname_join + '<'; auto type_names = tmpl_id.arg_type_names(); std::map<Label,std::shared_ptr<Type<Impl>>> types; auto it_placeholder = tmpl->type_names.begin(); for(auto it=type_names.begin(); (it != type_names.end()) && (it_placeholder != tmpl->type_names.end()); ) { // find type auto ty = find_type(m_mod, *it); if( !ty ) { std::stringstream strm; strm << node.location() << ": " << "failed to find type '" << *it << "' in instantiation of template '" << qname_join << "'"; throw std::runtime_error(strm.str()); } types[*it_placeholder] = ty; // append name module_name += *it; if( ++it != type_names.end() ) module_name += ','; ++it_placeholder; } module_name += '>'; // run Module_scanner inst->module = this->instantiate_module_template(module_name, tmpl->module_node, types); } else { if( typeid(node.module_name()) == typeid(ast::Qualified_name) ) { auto const& qn = dynamic_cast<ast::Qualified_name const&>(node.module_name()).name(); if( qn.size() > 1 ) { inst->module = find_by_path(m_mod, &Module<Impl>::modules, qn); } else { inst->module = find_module(m_mod, qn[0]); } } else { std::stringstream strm; strm << node.location() << "Expecting a qualified name as module for now (" << __func__ << ")"; throw std::runtime_error(strm.str()); } } if( !inst->module ) { std::stringstream strm; strm << node.location(); strm << ": module '" << module_name << "' not found."; throw std::runtime_error(strm.str()); } std::set<Label> matched_ports; for(auto& i : node.connection_items()) { if( typeid(*i) == typeid(ast::Connection_item) ) { auto& con_item = dynamic_cast<ast::Connection_item const&>(*i); auto port_name = con_item.port_name().identifier(); //auto signal_name = con_item.signal_name().identifier(); if( matched_ports.count(port_name) > 0 ) { std::stringstream strm; strm << con_item.port_name().location(); strm << ": Port already connected"; throw std::runtime_error(strm.str()); } std::shared_ptr<Port_assignment<Impl>> port_assign(new Port_assignment<Impl>()); port_assign->port = find_port(*(inst->module), port_name); if( !port_assign->port ) { std::stringstream strm; strm << con_item.port_name().location(); strm << ": port '" << port_name << "' not found."; throw std::runtime_error(strm.str()); } //port_assign->object = find_object(m_mod, signal_name); //if( !port_assign->object ) { //std::stringstream strm; //strm << con_item.signal_name().location(); //strm << ": assigned object '" << signal_name << "' not found."; //throw std::runtime_error(strm.str()); //} //if( !type_compatible(*(port_assign->port->type), *(port_assign->object->type)) ) { //std::stringstream strm; //strm << con_item.location(); //strm << ": incompatible types in port assignment: expected type '" //<< *(port_assign->port->type) //<< "' got '" //<< *(port_assign->object->type) << "'"; //throw std::runtime_error(strm.str()); //} inst->connection.push_back(port_assign); matched_ports.insert(port_name); } else if( typeid(*i) == typeid(ast::Identifier) ) { auto& obj_name = dynamic_cast<ast::Identifier const&>(*i).identifier(); auto assignee = find_object(m_mod, obj_name); if( !assignee ) { std::stringstream strm; strm << i->location() << ": object '" << obj_name << "' not found"; throw std::runtime_error(strm.str()); } auto assignee_socket = find_socket(m_mod, assignee->type->name); if( !assignee_socket ) { std::stringstream strm; strm << i->location() << ": object '" << obj_name << "' of type '" << assignee->type->name << "' is not a socket"; throw std::runtime_error(strm.str()); } for(auto assignee_port_pair : assignee_socket->elements) { auto port_name = assignee_port_pair.first; auto assignee_port = assignee_port_pair.second; auto searchit = assignee->type->elements.find(port_name); if( searchit != assignee->type->elements.end() ) { auto it = searchit->second; if( !type_compatible(*(it->type), *(assignee_port->type)) ) { std::stringstream strm; strm << i->location() << ": name match for port '" << port_name << "'" << " but no type match (expected: " << *(it->type) << ", got: " << *(assignee_port->type) << ")"; throw std::runtime_error(strm.str()); } if( matched_ports.count(assignee_port->name) > 0 ) { std::stringstream strm; strm << i->location() << ": port '" << assignee_port->name << "' already matched"; throw std::runtime_error(strm.str()); } std::shared_ptr<Port_assignment<Impl>> port_assign(new Port_assignment<Impl>); port_assign->port = it; // XXX assign object to element of composite type socket inst->connection.push_back(port_assign); matched_ports.insert(assignee_port->name); } } } else throw std::runtime_error("connection items should be either a list or a single identifier"); } m_mod.instantiations[inst->name] = inst; auto obj = std::make_shared<Object<Impl>>(); obj->name = inst->name; obj->type = inst->module->socket; m_mod.objects[obj->name] = obj; return inst; }
exprt dereferencet::read_object( const exprt &object, const exprt &offset, const typet &type) { const typet &object_type=ns.follow(object.type()); const typet &dest_type=ns.follow(type); // is the object an array with matching subtype? exprt simplified_offset=simplify_expr(offset, ns); // check if offset is zero if(simplified_offset.is_zero()) { // check type if(base_type_eq(object_type, dest_type, ns)) { return object; // trivial case } else if(type_compatible(object_type, dest_type)) { // the type differs, but we can do this with a typecast return typecast_exprt(object, dest_type); } } if(object.id()==ID_index) { const index_exprt &index_expr=to_index_expr(object); exprt index=index_expr.index(); // multiply index by object size exprt size=size_of_expr(object_type, ns); if(size.is_nil()) throw "dereference failed to get object size for index"; index.make_typecast(simplified_offset.type()); size.make_typecast(index.type()); exprt new_offset=plus_exprt(simplified_offset, mult_exprt(index, size)); return read_object(index_expr.array(), new_offset, type); } else if(object.id()==ID_member) { const member_exprt &member_expr=to_member_expr(object); const typet &compound_type= ns.follow(member_expr.struct_op().type()); if(compound_type.id()==ID_struct) { const struct_typet &struct_type= to_struct_type(compound_type); exprt member_offset=member_offset_expr( struct_type, member_expr.get_component_name(), ns); if(member_offset.is_nil()) throw "dereference failed to get member offset"; member_offset.make_typecast(simplified_offset.type()); exprt new_offset=plus_exprt(simplified_offset, member_offset); return read_object(member_expr.struct_op(), new_offset, type); } else if(compound_type.id()==ID_union) { // Unions are easy: the offset is always zero, // so simply pass down. return read_object(member_expr.struct_op(), offset, type); } } // check if we have an array with the right subtype if(object_type.id()==ID_array && base_type_eq(object_type.subtype(), dest_type, ns)) { // check proper alignment exprt size=size_of_expr(dest_type, ns); if(size.is_not_nil()) { mp_integer size_constant, offset_constant; if(!to_integer(simplify_expr(size, ns), size_constant) && !to_integer(simplified_offset, offset_constant) && (offset_constant%size_constant)==0) { // Yes! Can use index expression! mp_integer index_constant=offset_constant/size_constant; exprt index_expr=from_integer(index_constant, size.type()); return index_exprt(object, index_expr, dest_type); } } } // give up and use byte_extract return binary_exprt(object, byte_extract_id(), simplified_offset, dest_type); }
/* Return TRUE if no error and lhstype and rhstype are not error_type */ bool check_assignment(type lhstype, type rhstype, expression rhs, const char *context, data_declaration fundecl, const char *funname, int parmnum) { bool zerorhs = rhs && definite_zero(rhs); if (lhstype == error_type || rhstype == error_type) return FALSE; if (type_void(rhstype)) { error("void value not ignored as it ought to be"); return FALSE; } if (type_equal_unqualified(lhstype, rhstype)) return TRUE; if (type_arithmetic(lhstype) && type_arithmetic(rhstype)) { if (rhs) constant_overflow_warning(rhs->cst); return check_conversion(lhstype, rhstype); } if (parmnum && (type_qualifiers(lhstype) & transparent_qualifier)) { /* See if we can match any field of lhstype */ tag_declaration tag = type_tag(lhstype); field_declaration fields, marginal_field = NULL; /* I blame gcc for this horrible mess (and it's minor inconsistencies with the regular rules) */ /* pedantic warnings are skipped in here because we're already issuing a warning for the use of this construct */ for (fields = tag->fieldlist; fields; fields = fields->next) { type ft = fields->type; if (type_compatible(ft, rhstype)) break; if (!type_pointer(ft)) continue; if (type_pointer(rhstype)) { type ttl = type_points_to(ft), ttr = type_points_to(rhstype); bool goodmatch = assignable_pointer_targets(ttl, ttr, FALSE); /* Any non-function converts to a [const][volatile] void * and vice versa; otherwise, targets must be the same. Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if (goodmatch) { /* If this type won't generate any warnings, use it. */ if ((type_function(ttr) && type_function(ttl)) ? (((!type_const(ttl)) | type_const(ttr)) & ((!type_volatile(ttl)) | type_volatile(ttr))) : (((type_const(ttl)) | (!type_const(ttr))) & (type_volatile(ttl) | (!type_volatile(ttr))))) break; /* Keep looking for a better type, but remember this one. */ if (!marginal_field) marginal_field = fields; } } /* Can convert integer zero to any pointer type. */ /* Note that this allows passing *any* null pointer (gcc bug?) */ if (zerorhs) break; } if (fields || marginal_field) { if (!fields) { /* We have only a marginally acceptable member type; it needs a warning. */ type ttl = type_points_to(marginal_field->type), ttr = type_points_to(rhstype); ptrconversion_warnings(ttl, ttr, rhs, context, funname, parmnum, FALSE); } if (pedantic && !(fundecl && fundecl->in_system_header)) pedwarn("ANSI C prohibits argument conversion to union type"); return TRUE; } } if (type_pointer(lhstype) && type_pointer(rhstype)) { type ttl = type_points_to(lhstype), ttr = type_points_to(rhstype); bool goodmatch = assignable_pointer_targets(ttl, ttr, pedantic); /* Any non-function converts to a [const][volatile] void * and vice versa; otherwise, targets must be the same. Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if (goodmatch || (type_equal_unqualified(make_unsigned_type(ttl), make_unsigned_type(ttr)))) ptrconversion_warnings(ttl, ttr, rhs, context, funname, parmnum, pedantic); else warn_for_assignment("%s from incompatible pointer type", context, funname, parmnum); return check_conversion(lhstype, rhstype); } /* enum = ptr and ptr = enum counts as an error, so use type_integral */ else if (type_pointer(lhstype) && type_integral(rhstype)) { if (!zerorhs) warn_for_assignment("%s makes pointer from integer without a cast", context, funname, parmnum); return check_conversion(lhstype, rhstype); } else if (type_integral(lhstype) && type_pointer(rhstype)) { warn_for_assignment("%s makes integer from pointer without a cast", context, funname, parmnum); return check_conversion(lhstype, rhstype); } if (!context) if (funname) error("incompatible type for argument %d of `%s'", parmnum, funname); else error("incompatible type for argument %d of indirect function call", parmnum); else error("incompatible types in %s", context); return FALSE; }