/** * Return the smallest type that both t1 and t2 can be cast to without losing * information. * * e.g. * * join_types(unsignedbv_typet(32), unsignedbv_typet(16))=unsignedbv_typet(32) * join_types(signedbv_typet(16), unsignedbv_typet(16))=signedbv_typet(17) * join_types(signedbv_typet(32), signedbv_typet(32))=signedbv_typet(32) */ typet join_types(const typet &t1, const typet &t2) { // Handle the simple case first... if(t1==t2) { return t1; } // OK, they're not the same type. Are they both bitvectors? if(is_bitvector(t1) && is_bitvector(t2)) { // They are. That makes things easy! There are three cases to consider: // both types are unsigned, both types are signed or there's one of each. bitvector_typet b1=to_bitvector_type(t1); bitvector_typet b2=to_bitvector_type(t2); if(is_unsigned(b1) && is_unsigned(b2)) { // We just need to take the max of their widths. std::size_t width=std::max(b1.get_width(), b2.get_width()); return unsignedbv_typet(width); } else if(is_signed(b1) && is_signed(b2)) { // Again, just need to take the max of the widths. std::size_t width=std::max(b1.get_width(), b2.get_width()); return signedbv_typet(width); } else { // This is the (slightly) tricky case. If we have a signed and an // unsigned type, we're going to return a signed type. And to cast // an unsigned type to a signed type, we need the signed type to be // at least one bit wider than the unsigned type we're casting from. std::size_t signed_width=is_signed(t1) ? b1.get_width() : b2.get_width(); std::size_t unsigned_width=is_signed(t1) ? b2.get_width() : b1.get_width(); // unsigned_width++; std::size_t width=std::max(signed_width, unsigned_width); return signedbv_typet(width); } } std::cerr << "Tried to join types: " << t1.pretty() << " and " << t2.pretty() << '\n'; assert(!"Couldn't join types"); }
bool languaget::from_type( const typet &type, std::string &code, const namespacet &ns) { code=type.pretty(); return false; }
void jsil_typecheckt::make_type_compatible( exprt &expr, const typet &type, bool must) { if(type.id().empty() || type.is_nil()) { err_location(expr); error() << "make_type_compatible got empty type: " << expr.pretty() << eom; throw 0; } if(expr.type().id().empty() || expr.type().is_nil()) { // Type is not yet set update_expr_type(expr, type); return; } if(must) { if(jsil_incompatible_types(expr.type(), type)) { err_location(expr); error() << "failed to typecheck expr " << expr.pretty() << " with type " << expr.type().pretty() << "; required type " << type.pretty() << eom; throw 0; } } else if(!jsil_is_subtype(type, expr.type())) { // Types are not compatible typet upper=jsil_union(expr.type(), type); update_expr_type(expr, upper); } }
void cpp_typecheckt::typecheck_type(typet &type) { assert(!type.id().empty()); assert(type.is_not_nil()); try { cpp_convert_plain_type(type); } catch(const char *err) { error().source_location=type.source_location(); error() << err << eom; throw 0; } catch(const std::string &err) { error().source_location=type.source_location(); error() << err << eom; throw 0; } if(type.id()==ID_cpp_name) { c_qualifierst qualifiers(type); cpp_namet cpp_name; cpp_name.swap(type); exprt symbol_expr=resolve( cpp_name, cpp_typecheck_resolvet::wantt::TYPE, cpp_typecheck_fargst()); if(symbol_expr.id()!=ID_type) { error().source_location=type.source_location(); error() << "error: expected type" << eom; throw 0; } type=symbol_expr.type(); assert(type.is_not_nil()); if(type.get_bool(ID_C_constant)) qualifiers.is_constant = true; qualifiers.write(type); } else if(type.id()==ID_struct || type.id()==ID_union) { typecheck_compound_type(to_struct_union_type(type)); } else if(type.id()==ID_pointer) { // the pointer might have a qualifier, but do subtype first typecheck_type(type.subtype()); // Check if it is a pointer-to-member if(type.find("to-member").is_not_nil()) { // these can point either to data members or member functions // of a class typet &class_object=static_cast<typet &>(type.add("to-member")); if(class_object.id()==ID_cpp_name) { assert(class_object.get_sub().back().id()=="::"); class_object.get_sub().pop_back(); } typecheck_type(class_object); // there may be parameters if this is a pointer to member function if(type.subtype().id()==ID_code) { irept::subt ¶meters=type.subtype().add(ID_parameters).get_sub(); if(parameters.empty() || parameters.front().get(ID_C_base_name)!=ID_this) { // Add 'this' to the parameters exprt a0(ID_parameter); a0.set(ID_C_base_name, ID_this); a0.type().id(ID_pointer); a0.type().subtype() = class_object; parameters.insert(parameters.begin(), a0); } } } } else if(type.id()==ID_array) { exprt &size_expr=to_array_type(type).size(); if(size_expr.is_not_nil()) { typecheck_expr(size_expr); simplify(size_expr, *this); } typecheck_type(type.subtype()); if(type.subtype().get_bool(ID_C_constant)) type.set(ID_C_constant, true); if(type.subtype().get_bool(ID_C_volatile)) type.set(ID_C_volatile, true); } else if(type.id()==ID_code) { code_typet &code_type=to_code_type(type); typecheck_type(code_type.return_type()); code_typet::parameterst ¶meters=code_type.parameters(); for(auto ¶m : parameters) { typecheck_type(param.type()); // see if there is a default value if(param.has_default_value()) { typecheck_expr(param.default_value()); implicit_typecast(param.default_value(), param.type()); } } } else if(type.id()==ID_template) { typecheck_type(type.subtype()); } else if(type.id()==ID_c_enum) { typecheck_enum_type(type); } else if(type.id()==ID_c_enum_tag) { } else if(type.id()==ID_c_bit_field) { typecheck_c_bit_field_type(to_c_bit_field_type(type)); } else if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_bool || type.id()==ID_floatbv || type.id()==ID_fixedbv || type.id()==ID_empty) { } else if(type.id()==ID_symbol) { } else if(type.id()==ID_constructor || type.id()==ID_destructor) { } else if(type.id()=="cpp-cast-operator") { } else if(type.id()=="cpp-template-type") { } else if(type.id()==ID_typeof) { exprt e=static_cast<const exprt &>(type.find(ID_expr_arg)); if(e.is_nil()) { typet tmp_type= static_cast<const typet &>(type.find(ID_type_arg)); if(tmp_type.id()==ID_cpp_name) { // this may be ambiguous -- it can be either a type or // an expression cpp_typecheck_fargst fargs; exprt symbol_expr=resolve( to_cpp_name(static_cast<const irept &>(tmp_type)), cpp_typecheck_resolvet::wantt::BOTH, fargs); type=symbol_expr.type(); } else { typecheck_type(tmp_type); type=tmp_type; } } else { typecheck_expr(e); type=e.type(); } } else if(type.id()==ID_decltype) { exprt e=static_cast<const exprt &>(type.find(ID_expr_arg)); typecheck_expr(e); type=e.type(); } else if(type.id()==ID_unassigned) { // ignore, for template parameter guessing } else if(type.id()==ID_template_class_instance) { // ok (internally generated) } else if(type.id()==ID_block_pointer) { // This is an Apple extension for lambda-like constructs. // http://thirdcog.eu/pwcblocks/ } else if(type.id()==ID_nullptr) { } else { error().source_location=type.source_location(); error() << "unexpected cpp type: " << type.pretty() << eom; throw 0; } assert(type.is_not_nil()); }
void cpp_typecheckt::typecheck_type(typet &type) { assert(type.id() != ""); assert(type.is_not_nil()); try { cpp_convert_plain_type(type); } catch(const char *error) { err_location(type); str << error; throw 0; } catch(const std::string &error) { err_location(type); str << error; throw 0; } if(type.id() == "cpp-name") { c_qualifierst qualifiers(type); cpp_namet cpp_name; cpp_name.swap(type); exprt symbol_expr = resolve(cpp_name, cpp_typecheck_resolvet::TYPE, cpp_typecheck_fargst()); if(symbol_expr.id() != "type") { err_location(type); str << "error: expected type"; throw 0; } type = symbol_expr.type(); assert(type.is_not_nil()); if(type.cmt_constant()) qualifiers.is_constant = true; qualifiers.write(type); } else if(type.id() == "struct" || type.id() == "union") { typecheck_compound_type(type); } else if(type.id() == "pointer") { // the pointer might have a qualifier, but do subtype first typecheck_type(type.subtype()); // Check if it is a pointer-to-member if(type.find("to-member").is_not_nil()) { // these can point either to data members or member functions // of a class typet &class_object = static_cast<typet &>(type.add("to-member")); if(class_object.id() == "cpp-name") { assert(class_object.get_sub().back().id() == "::"); class_object.get_sub().pop_back(); } typecheck_type(class_object); // there may be arguments if this is a pointer to member function if(type.subtype().id() == "code") { irept::subt &args = type.subtype().add("arguments").get_sub(); if(args.empty() || args.front().cmt_base_name() != "this") { // Add 'this' to the arguments exprt a0("argument"); a0.cmt_base_name("this"); a0.type().id("pointer"); a0.type().subtype() = class_object; args.insert(args.begin(), a0); } } } // now do qualifier if(type.find("#qualifier").is_not_nil()) { typet &t = static_cast<typet &>(type.add("#qualifier")); cpp_convert_plain_type(t); c_qualifierst q(t); q.write(type); } type.remove("#qualifier"); } else if(type.id() == "array") { exprt &size_expr = to_array_type(type).size(); if(size_expr.is_nil()) type.id("incomplete_array"); else typecheck_expr(size_expr); // TODO: If is a incomplete_array, it should always // have initializers, except for catch declaration typecheck_type(type.subtype()); if(type.subtype().cmt_constant()) type.cmt_constant(true); if(type.subtype().cmt_volatile()) type.set("#volatile", true); } else if(type.id() == "code") { code_typet &code_type = to_code_type(type); typecheck_type(code_type.return_type()); code_typet::argumentst &arguments = code_type.arguments(); for(auto &argument : arguments) { typecheck_type(argument.type()); // see if there is a default value if(argument.has_default_value()) { typecheck_expr(argument.default_value()); implicit_typecast(argument.default_value(), argument.type()); } } } else if(type.id() == "template") { typecheck_type(type.subtype()); } else if(type.id() == "c_enum") { typecheck_enum_type(type); } else if( type.id() == "unsignedbv" || type.id() == "signedbv" || type.id() == "bool" || type.id() == "floatbv" || type.id() == "fixedbv" || type.id() == "empty") { } else if(type.id() == "symbol") { } else if(type.id() == "constructor" || type.id() == "destructor") { } else if(type.id() == "cpp-cast-operator") { } else if(type.id() == "cpp-template-type") { } else if(type.id() == "typeof") { exprt e = static_cast<const exprt &>(type.find("expr")); if(e.is_nil()) { typet tmp_type = static_cast<const typet &>(type.find("sizeof-type")); if(tmp_type.id() == "cpp-name") { // this may be ambiguous -- it can be either a type or // an expression cpp_typecheck_fargst fargs; exprt symbol_expr = resolve( to_cpp_name(static_cast<const irept &>(tmp_type)), cpp_typecheck_resolvet::BOTH, fargs); type = symbol_expr.type(); } else { typecheck_type(tmp_type); type = tmp_type; } } else { typecheck_expr(e); type = e.type(); } } else if(type.id() == "decltype") { exprt e = static_cast<const exprt &>(type.find("expr_arg")); typecheck_expr(e); type = e.type(); } else if(type.id() == "unassigned") { // ignore, for template argument guessing } else if(type.id() == "ellipsis") { } else { err_location(type); str << "unexpected type: " << type.pretty(); throw 0; } assert(type.is_not_nil()); }
bool value_set_dereferencet::memory_model_bytes( exprt &value, const typet &to_type, const guardt &guard, const exprt &offset) { const typet from_type=value.type(); // We simply refuse to convert to/from code. if(from_type.id()==ID_code || to_type.id()==ID_code) return false; // We won't do this without a commitment to an endianness. if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::NO_ENDIANNESS) return false; // But everything else we will try! // We just rely on byte_extract to do the job! exprt result; // See if we have an array of bytes already, // and we want something byte-sized. if(ns.follow(from_type).id()==ID_array && pointer_offset_size(ns.follow(from_type).subtype(), ns)==1 && pointer_offset_size(to_type, ns)==1 && is_a_bv_type(ns.follow(from_type).subtype()) && is_a_bv_type(to_type)) { // yes, can use 'index' result=index_exprt(value, offset, ns.follow(from_type).subtype()); // possibly need to convert if(!base_type_eq(result.type(), to_type, ns)) result.make_typecast(to_type); } else { // no, use 'byte_extract' result=exprt(byte_extract_id(), to_type); result.copy_to_operands(value, offset); } value=result; // are we within the bounds? if(options.get_bool_option("pointer-check")) { // upper bound { exprt from_width=size_of_expr(from_type, ns); INVARIANT( from_width.is_not_nil(), "unknown or invalid type size:\n"+from_type.pretty()); exprt to_width= to_type.id()==ID_empty? from_integer(0, size_type()):size_of_expr(to_type, ns); INVARIANT( to_width.is_not_nil(), "unknown or invalid type size:\n"+to_type.pretty()); INVARIANT( from_width.type()==to_width.type(), "type mismatch on result of size_of_expr"); minus_exprt bound(from_width, to_width); if(bound.type()!=offset.type()) bound.make_typecast(offset.type()); binary_relation_exprt offset_upper_bound(offset, ID_gt, bound); guardt tmp_guard(guard); tmp_guard.add(offset_upper_bound); dereference_callback.dereference_failure( "pointer dereference", "object upper bound", tmp_guard); } // lower bound is easy if(!offset.is_zero()) { binary_relation_exprt offset_lower_bound( offset, ID_lt, from_integer(0, offset.type())); guardt tmp_guard(guard); tmp_guard.add(offset_lower_bound); dereference_callback.dereference_failure( "pointer dereference", "object lower bound", tmp_guard); } } return true; }
bool base_type_eqt::base_type_eq_rec( const typet &type1, const typet &type2) { if(type1==type2) return true; #if 0 std::cout << "T1: " << type1.pretty() << std::endl; std::cout << "T2: " << type2.pretty() << std::endl; #endif // loop avoidance if((type1.id()==ID_symbol || type1.id()==ID_c_enum_tag || type1.id()==ID_struct_tag || type1.id()==ID_union_tag) && type2.id()==type1.id()) { // already in same set? if(identifiers.make_union( type1.get(ID_identifier), type2.get(ID_identifier))) return true; } if(type1.id()==ID_symbol || type1.id()==ID_c_enum_tag || type1.id()==ID_struct_tag || type1.id()==ID_union_tag) { const symbolt &symbol= ns.lookup(type1.get(ID_identifier)); if(!symbol.is_type) return false; return base_type_eq_rec(symbol.type, type2); } if(type2.id()==ID_symbol || type2.id()==ID_c_enum_tag || type2.id()==ID_struct_tag || type2.id()==ID_union_tag) { const symbolt &symbol= ns.lookup(type2.get(ID_identifier)); if(!symbol.is_type) return false; return base_type_eq_rec(type1, symbol.type); } if(type1.id()!=type2.id()) return false; if(type1.id()==ID_struct || type1.id()==ID_union) { const struct_union_typet::componentst &components1= to_struct_union_type(type1).components(); const struct_union_typet::componentst &components2= to_struct_union_type(type2).components(); if(components1.size()!=components2.size()) return false; for(unsigned i=0; i<components1.size(); i++) { const typet &subtype1=components1[i].type(); const typet &subtype2=components2[i].type(); if(!base_type_eq_rec(subtype1, subtype2)) return false; if(components1[i].get_name()!=components2[i].get_name()) return false; } return true; } else if(type1.id()==ID_incomplete_struct) { return true; } else if(type1.id()==ID_incomplete_union) { return true; } else if(type1.id()==ID_code) { const code_typet::parameterst ¶meters1= to_code_type(type1).parameters(); const code_typet::parameterst ¶meters2= to_code_type(type2).parameters(); if(parameters1.size()!=parameters2.size()) return false; for(unsigned i=0; i<parameters1.size(); i++) { const typet &subtype1=parameters1[i].type(); const typet &subtype2=parameters2[i].type(); if(!base_type_eq_rec(subtype1, subtype2)) return false; } const typet &return_type1=to_code_type(type1).return_type(); const typet &return_type2=to_code_type(type2).return_type(); if(!base_type_eq_rec(return_type1, return_type2)) return false; return true; } else if(type1.id()==ID_pointer) { return base_type_eq_rec( to_pointer_type(type1).subtype(), to_pointer_type(type2).subtype()); } else if(type1.id()==ID_array) { if(!base_type_eq_rec( to_array_type(type1).subtype(), to_array_type(type2).subtype())) return false; if(to_array_type(type1).size()!=to_array_type(type2).size()) return false; return true; } else if(type1.id()==ID_incomplete_array) { return base_type_eq_rec( to_incomplete_array_type(type1).subtype(), to_incomplete_array_type(type2).subtype()); } // the below will go away typet tmp1(type1), tmp2(type2); base_type(tmp1, ns); base_type(tmp2, ns); return tmp1==tmp2; }