bool full_eq(const irept &i1, const irept &i2) { #ifdef SHARING if(i1.data==i2.data) return true; #endif if(i1.id()!=i2.id()) return false; const irept::subt &i1_sub=i1.get_sub(); const irept::subt &i2_sub=i2.get_sub(); const irept::named_subt &i1_named_sub=i1.get_named_sub(); const irept::named_subt &i2_named_sub=i2.get_named_sub(); const irept::named_subt &i1_comments=i1.get_comments(); const irept::named_subt &i2_comments=i2.get_comments(); if(i1_sub.size() !=i2_sub.size()) return false; if(i1_named_sub.size()!=i2_named_sub.size()) return false; if(i1_comments.size() !=i2_comments.size()) return false; for(unsigned i=0; i<i1_sub.size(); i++) if(!full_eq(i1_sub[i], i2_sub[i])) return false; { irept::named_subt::const_iterator i1_it=i1_named_sub.begin(); irept::named_subt::const_iterator i2_it=i2_named_sub.begin(); for(; i1_it!=i1_named_sub.end(); i1_it++, i2_it++) if(i1_it->first!=i2_it->first || !full_eq(i1_it->second, i2_it->second)) return false; } { irept::named_subt::const_iterator i1_it=i1_comments.begin(); irept::named_subt::const_iterator i2_it=i2_comments.begin(); for(; i1_it!=i1_comments.end(); i1_it++, i2_it++) if(i1_it->first!=i2_it->first || !full_eq(i1_it->second, i2_it->second)) return false; } return true; }
void c_typecastt::implicit_typecast_followed( exprt &expr, const typet &src_type, const typet &orig_dest_type, const typet &dest_type) { // do transparent union if(dest_type.id()==ID_union && dest_type.get_bool(ID_C_transparent_union) && src_type.id()!=ID_union) { // The argument corresponding to a transparent union type can be of any // type in the union; no explicit cast is required. // GCC docs say: // If the union member type is a pointer, qualifiers like const on the // referenced type must be respected, just as with normal pointer // conversions. // But it is accepted, and Clang doesn't even emit a warning (GCC 4.7 does) typet src_type_no_const=src_type; if(src_type.id()==ID_pointer && src_type.subtype().get_bool(ID_C_constant)) src_type_no_const.subtype().remove(ID_C_constant); // Check union members. const union_typet &dest_union_type=to_union_type(dest_type); for(union_typet::componentst::const_iterator it=dest_union_type.components().begin(); it!=dest_union_type.components().end(); it++) { if(!check_c_implicit_typecast(src_type_no_const, it->type())) { // build union constructor exprt union_expr(ID_union, orig_dest_type); union_expr.move_to_operands(expr); if(!full_eq(src_type, src_type_no_const)) do_typecast(union_expr.op0(), src_type_no_const); union_expr.set(ID_component_name, it->get_name()); expr=union_expr; return; // ok } } } if(dest_type.id()==ID_pointer) { // special case: 0 == NULL if(simplify_expr(expr, ns).is_zero() && ( src_type.id()==ID_unsignedbv || src_type.id()==ID_signedbv || src_type.id()==ID_natural || src_type.id()==ID_integer)) { expr=exprt(ID_constant, orig_dest_type); expr.set(ID_value, ID_NULL); return; // ok } if(src_type.id()==ID_pointer || src_type.id()==ID_array) { // we are quite generous about pointers const typet &src_sub=ns.follow(src_type.subtype()); const typet &dest_sub=ns.follow(dest_type.subtype()); if(is_void_pointer(src_type) || is_void_pointer(dest_type)) { // from/to void is always good } else if(src_sub.id()==ID_code && dest_sub.id()==ID_code) { // very generous: // between any two function pointers it's ok } else if(base_type_eq(src_sub, dest_sub, ns)) { // ok } else if((is_number(src_sub) || src_sub.id()==ID_c_enum || src_sub.id()==ID_c_enum_tag) && (is_number(dest_sub) || dest_sub.id()==ID_c_enum || src_sub.id()==ID_c_enum_tag)) { // Also generous: between any to scalar types it's ok. // We should probably check the size. } else warnings.push_back("incompatible pointer types"); // check qualifiers /* if(src_type.subtype().get_bool(ID_C_constant) && !dest_type.subtype().get_bool(ID_C_constant)) warnings.push_back("disregarding const"); */ if(src_type.subtype().get_bool(ID_C_volatile) && !dest_type.subtype().get_bool(ID_C_volatile)) warnings.push_back("disregarding volatile"); if(src_type==dest_type) { expr.type()=src_type; // because of qualifiers } else do_typecast(expr, orig_dest_type); return; // ok } } if(check_c_implicit_typecast(src_type, dest_type)) errors.push_back("implicit conversion not permitted"); else if(src_type!=dest_type) do_typecast(expr, orig_dest_type); }