void ansi_c_convert_typet::read(const typet &type) { clear(); source_location=type.source_location(); read_rec(type); if(!aligned && type.find(ID_C_alignment).is_not_nil()) { aligned=true; alignment=static_cast<const exprt &>(type.find(ID_C_alignment)); } }
void cpp_declarationt::name_anon_struct_union(typet &dest) { // We name any anon struct/unions according to the first // declarator. No need to do anon enums, which get // a name based on the enum elements. if(dest.id()==ID_struct || dest.id()==ID_union) { if(dest.find(ID_tag).is_nil()) { // it's anonymous const declaratorst &d=declarators(); if(!d.empty() && d.front().name().is_simple_name()) { // Anon struct/unions without declarator are pretty // useless, but still possible. irep_idt base_name="anon-"+id2string(d.front().name().get_base_name()); dest.set(ID_tag, cpp_namet(base_name)); dest.set(ID_C_is_anonymous, true); } } } else if(dest.id()==ID_merged_type) { Forall_subtypes(it, dest) name_anon_struct_union(*it); } }
void c_typecheck_baset::typecheck_typeof_type(typet &type) { // retain the qualifiers as is c_qualifierst c_qualifiers; c_qualifiers.read(type); if(!((const exprt &)type).has_operands()) { typet t=static_cast<const typet &>(type.find(ID_type_arg)); typecheck_type(t); type.swap(t); } else { exprt expr=((const exprt &)type).op0(); typecheck_expr(expr); // undo an implicit address-of if(expr.id()==ID_address_of && expr.get_bool(ID_C_implicit)) { assert(expr.operands().size()==1); exprt tmp; tmp.swap(expr.op0()); expr.swap(tmp); } type.swap(expr.type()); } c_qualifiers.write(type); }
void java_bytecode_parsert::get_class_refs_rec(const typet &src) { if(src.id()==ID_code) { const code_typet &ct=to_code_type(src); const typet &rt=ct.return_type(); get_class_refs_rec(rt); for(const auto &p : ct.parameters()) get_class_refs_rec(p.type()); } else if(src.id()==ID_symbol) { irep_idt name=src.get(ID_C_base_name); if(has_prefix(id2string(name), "array[")) { const typet &element_type= static_cast<const typet &>(src.find(ID_C_element_type)); get_class_refs_rec(element_type); } else parse_tree.class_refs.insert(name); } else if(src.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(src); for(const auto &c : struct_type.components()) get_class_refs_rec(c.type()); } else if(src.id()==ID_pointer) get_class_refs_rec(src.subtype()); }
void c_typecheck_baset::typecheck_symbol_type(typet &type) { { // add prefix symbol_typet &symbol_type=to_symbol_type(type); symbol_type.set_identifier(add_language_prefix(symbol_type.get_identifier())); } // adjust identifier, if needed replace_symbol(type); const irep_idt &identifier= to_symbol_type(type).get_identifier(); symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) { err_location(type); str << "type symbol `" << identifier << "' not found"; throw 0; } const symbolt &symbol=s_it->second; if(!symbol.is_type) { err_location(type); throw "expected type symbol"; } if(symbol.is_macro) { // overwrite, but preserve (add) any qualifiers and other flags c_qualifierst c_qualifiers(type); bool is_packed=type.get_bool(ID_C_packed); irept alignment=type.find(ID_C_alignment); c_qualifiers+=c_qualifierst(symbol.type); type=symbol.type; c_qualifiers.write(type); if(is_packed) type.set(ID_C_packed, true); if(alignment.is_not_nil()) type.set(ID_C_alignment, alignment); } // CPROVER extensions if(symbol.base_name=="__CPROVER_rational") { type=rational_typet(); } else if(symbol.base_name=="__CPROVER_integer") { type=integer_typet(); } }
void c_typecheck_baset::typecheck_type(typet &type) { // we first convert, and then check // do we have alignment? if(type.find(ID_C_alignment).is_not_nil()) { exprt &alignment=static_cast<exprt &>(type.add(ID_C_alignment)); if(alignment.id()!=ID_default) { typecheck_expr(alignment); make_constant(alignment); } } if(type.id()==ID_code) typecheck_code_type(to_code_type(type)); else if(type.id()==ID_array) typecheck_array_type(to_array_type(type)); else if(type.id()==ID_pointer) typecheck_type(type.subtype()); else if(type.id()==ID_struct || type.id()==ID_union) typecheck_compound_type(to_struct_union_type(type)); else if(type.id()==ID_c_enum) { } else if(type.id()==ID_c_bitfield) typecheck_c_bit_field_type(type); else if(type.id()==ID_typeof) typecheck_typeof_type(type); else if(type.id()==ID_symbol) typecheck_symbol_type(type); else if(type.id()==ID_vector) typecheck_vector_type(to_vector_type(type)); else if(type.id()==ID_custom_unsignedbv || type.id()==ID_custom_signedbv || type.id()==ID_custom_floatbv || type.id()==ID_custom_fixedbv) typecheck_custom_type(type); // do a bit of rule checking if(type.get_bool(ID_C_restricted) && type.id()!=ID_pointer && type.id()!=ID_array) { err_location(type); error("only a pointer can be 'restrict'"); throw 0; } }
code_function_callt get_destructor( const namespacet &ns, const typet &type) { if(type.id()==ID_symbol) { return get_destructor(ns, ns.follow(type)); } else if(type.id()==ID_struct) { const exprt &methods=static_cast<const exprt&>(type.find(ID_methods)); forall_operands(it, methods) { if(it->type().id()==ID_code) { const code_typet &code_type=to_code_type(it->type()); if(code_type.return_type().id()==ID_destructor && code_type.parameters().size()==1) { const typet &arg_type=code_type.parameters().front().type(); if(arg_type.id()==ID_pointer && ns.follow(arg_type.subtype())==type) { exprt symbol_expr(ID_symbol, it->type()); symbol_expr.set(ID_identifier, it->get(ID_name)); code_function_callt function_call; function_call.function()=symbol_expr; return function_call; } } } } } return static_cast<const code_function_callt &>(get_nil_irep()); }
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 cpp_typecheckt::cpp_is_pod(const typet &type) const { if(type.id()==ID_struct) { // Not allowed in PODs: // * Non-PODs // * Constructors/Destructors // * virtuals // * private/protected, unless static // * overloading assignment operator // * Base classes const struct_typet &struct_type=to_struct_type(type); if(!type.find(ID_bases).get_sub().empty()) return false; const struct_typet::componentst &components= struct_type.components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_bool(ID_is_type)) continue; if(it->get_base_name()=="operator=") return false; if(it->get_bool(ID_is_virtual)) return false; const typet &sub_type=it->type(); if(sub_type.id()==ID_code) { if(it->get_bool(ID_is_virtual)) return false; const typet &return_type=to_code_type(sub_type).return_type(); if(return_type.id()==ID_constructor || return_type.id()==ID_destructor) return false; } else if(it->get(ID_access)!=ID_public && !it->get_bool(ID_is_static)) return false; if(!cpp_is_pod(sub_type)) return false; } return true; } else if(type.id()==ID_array) { return cpp_is_pod(type.subtype()); } else if(type.id()==ID_pointer) { if(is_reference(type)) // references are not PODs return false; // but pointers are PODs! return true; } else if(type.id()==ID_symbol) { const symbolt &symb=lookup(type.get(ID_identifier)); assert(symb.is_type); return cpp_is_pod(symb.type); } // everything else is POD return true; }
exprt c_sizeoft::sizeof_rec(const typet &type) { exprt dest; if(type.id()==ID_signedbv || type.id()==ID_unsignedbv || type.id()==ID_floatbv || type.id()==ID_fixedbv || type.id()==ID_c_enum || type.id()==ID_incomplete_c_enum) { // We round up to bytes. // See special treatment for bit-fields below. unsigned bits=type.get_int(ID_width); unsigned bytes=bits/8; if((bits%8)!=0) bytes++; dest=from_integer(bytes, size_type()); } else if(type.id()==ID_pointer) { // the following is an MS extension if(type.get_bool(ID_C_ptr32)) return from_integer(4, size_type()); unsigned bits=config.ansi_c.pointer_width; unsigned bytes=bits/8; if((bits%8)!=0) bytes++; dest=from_integer(bytes, size_type()); } else if(type.id()==ID_bool) { // We fit booleans into a byte. dest=from_integer(1, size_type()); } else if(type.id()==ID_array) { const exprt &size_expr= to_array_type(type).size(); if(size_expr.is_nil()) { // treated like an empty array dest=from_integer(0, size_type()); } else { exprt tmp_dest=sizeof_rec(type.subtype()); if(tmp_dest.is_nil()) return tmp_dest; mp_integer a, b; if(!to_integer(tmp_dest, a) && !to_integer(size_expr, b)) { dest=from_integer(a*b, size_type()); } else { dest.id(ID_mult); dest.type()=size_type(); dest.copy_to_operands(size_expr); dest.move_to_operands(tmp_dest); c_implicit_typecast(dest.op0(), dest.type(), ns); c_implicit_typecast(dest.op1(), dest.type(), ns); } } } else if(type.id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(type).components(); dest=from_integer(0, size_type()); mp_integer bit_field_width=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &sub_type=ns.follow(it->type()); if(it->get_bool(ID_is_type)) { } else if(sub_type.id()==ID_code) { } else if(it->get_is_bit_field()) { // this needs to be a signedbv/unsignedbv/enum if(sub_type.id()!=ID_signedbv && sub_type.id()!=ID_unsignedbv && sub_type.id()!=ID_c_enum) return nil_exprt(); // We just sum them up. // This assumes they are properly padded. bit_field_width+=sub_type.get_int(ID_width); } else { exprt tmp=sizeof_rec(sub_type); if(tmp.is_nil()) return tmp; dest=plus_exprt(dest, tmp); } } if(bit_field_width!=0) dest=plus_exprt(dest, from_integer(bit_field_width/8, size_type())); } else if(type.id()==ID_union) { const irept::subt &components= type.find(ID_components).get_sub(); mp_integer max_size=0; forall_irep(it, components) { if(it->get_bool(ID_is_type)) continue; const typet &sub_type=static_cast<const typet &>(it->find(ID_type)); if(sub_type.id()==ID_code) { } else { exprt tmp=sizeof_rec(sub_type); if(tmp.is_nil()) return tmp; simplify(tmp, ns); mp_integer tmp_int; if(to_integer(tmp, tmp_int)) return static_cast<const exprt &>(get_nil_irep()); if(tmp_int>max_size) max_size=tmp_int; } } dest=from_integer(max_size, size_type()); } else if(type.id()==ID_symbol)
unsigned interpretert::get_size(const typet &type) const { if(type.id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(type).components(); unsigned sum=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &sub_type=it->type(); if(sub_type.id()!=ID_code) sum+=get_size(sub_type); } return sum; } else if(type.id()==ID_union) { const union_typet::componentst &components= to_union_type(type).components(); unsigned max_size=0; for(union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &sub_type=it->type(); if(sub_type.id()!=ID_code) max_size=std::max(max_size, get_size(sub_type)); } return max_size; } else if(type.id()==ID_array) { const exprt &size_expr=static_cast<const exprt &>(type.find(ID_size)); unsigned subtype_size=get_size(type.subtype()); mp_integer i; if(!to_integer(size_expr, i)) return subtype_size*integer2unsigned(i); else return subtype_size; } else if(type.id()==ID_symbol) { return get_size(ns.follow(type)); } else return 1; }
void c_typecheck_baset::typecheck_custom_type(typet &type) { // they all have a width exprt size_expr= static_cast<const exprt &>(type.find(ID_size)); typecheck_expr(size_expr); source_locationt source_location=size_expr.source_location(); make_constant_index(size_expr); mp_integer size_int; if(to_integer(size_expr, size_int)) { error().source_location=source_location; error() << "failed to convert bit vector width to constant" << eom; throw 0; } if(size_int<1) { error().source_location=source_location; error() << "bit vector width invalid" << eom; throw 0; } type.remove(ID_size); type.set(ID_width, integer2string(size_int)); // depending on type, there may be a number of fractional bits if(type.id()==ID_custom_unsignedbv) type.id(ID_unsignedbv); else if(type.id()==ID_custom_signedbv) type.id(ID_signedbv); else if(type.id()==ID_custom_fixedbv) { type.id(ID_fixedbv); exprt f_expr= static_cast<const exprt &>(type.find(ID_f)); source_locationt source_location=f_expr.find_source_location(); typecheck_expr(f_expr); make_constant_index(f_expr); mp_integer f_int; if(to_integer(f_expr, f_int)) { error().source_location=source_location; error() << "failed to convert number of fraction bits to constant" << eom; throw 0; } if(f_int<0 || f_int>size_int) { error().source_location=source_location; error() << "fixedbv fraction width invalid" << eom; throw 0; } type.remove(ID_f); type.set(ID_integer_bits, integer2string(size_int-f_int)); } else if(type.id()==ID_custom_floatbv) { type.id(ID_floatbv); exprt f_expr= static_cast<const exprt &>(type.find(ID_f)); source_locationt source_location=f_expr.find_source_location(); typecheck_expr(f_expr); make_constant_index(f_expr); mp_integer f_int; if(to_integer(f_expr, f_int)) { error().source_location=source_location; error() << "failed to convert number of fraction bits to constant" << eom; throw 0; } if(f_int<1 || f_int+1>=size_int) { error().source_location=source_location; error() << "floatbv fraction width invalid" << eom; throw 0; } type.remove(ID_f); type.set(ID_f, integer2string(f_int)); } else assert(false); }
void c_typecheck_baset::typecheck_c_enum_type(typet &type) { // These come with the declarations // of the enum constants as operands. exprt &as_expr=static_cast<exprt &>(static_cast<irept &>(type)); source_locationt source_location=type.source_location(); // We allow empty enums in the grammar to get better // error messages. if(as_expr.operands().empty()) { error().source_location=source_location; error() << "empty enum" << eom; throw 0; } // enums start at zero; // we also track min and max to find a nice base type mp_integer value=0, min_value=0, max_value=0; std::list<c_enum_typet::c_enum_membert> enum_members; // We need to determine a width, and a signedness // to obtain an 'underlying type'. // We just do int, but gcc might pick smaller widths // if the type is marked as 'packed'. // gcc/clang may also pick a larger width. Visual Studio doesn't. for(auto &op : as_expr.operands()) { ansi_c_declarationt &declaration=to_ansi_c_declaration(op); exprt &v=declaration.declarator().value(); if(v.is_not_nil()) // value given? { exprt tmp_v=v; typecheck_expr(tmp_v); add_rounding_mode(tmp_v); simplify(tmp_v, *this); if(tmp_v.is_true()) value=1; else if(tmp_v.is_false()) value=0; else if(!to_integer(tmp_v, value)) { } else { error().source_location=v.source_location(); error() << "enum is not a constant"; throw 0; } } if(value<min_value) min_value=value; if(value>max_value) max_value=value; typet constant_type= enum_constant_type(min_value, max_value); v=from_integer(value, constant_type); declaration.type()=constant_type; typecheck_declaration(declaration); irep_idt base_name= declaration.declarator().get_base_name(); irep_idt identifier= declaration.declarator().get_name(); // store c_enum_typet::c_enum_membert member; member.set_identifier(identifier); member.set_base_name(base_name); member.set_value(integer2string(value)); enum_members.push_back(member); // produce value for next constant ++value; } // Remove these now; we add them to the // c_enum symbol later. as_expr.operands().clear(); bool is_packed=type.get_bool(ID_C_packed); // tag? if(type.find(ID_tag).is_nil()) { // None, it's anonymous. We generate a tag. std::string anon_identifier="#anon_enum"; for(const auto &member : enum_members) { anon_identifier+='$'; anon_identifier+=id2string(member.get_base_name()); anon_identifier+='='; anon_identifier+=id2string(member.get_value()); } if(is_packed) anon_identifier+="#packed"; type.add(ID_tag).set(ID_identifier, anon_identifier); } irept &tag=type.add(ID_tag); irep_idt base_name=tag.get(ID_C_base_name); irep_idt identifier=tag.get(ID_identifier); // Put into symbol table symbolt enum_tag_symbol; enum_tag_symbol.is_type=true; enum_tag_symbol.type=type; enum_tag_symbol.location=source_location; enum_tag_symbol.is_file_local=true; enum_tag_symbol.base_name=base_name; enum_tag_symbol.name=identifier; // throw in the enum members as 'body' irept::subt &body=enum_tag_symbol.type.add(ID_body).get_sub(); for(const auto &member : enum_members) body.push_back(member); // We use a subtype to store the underlying type. typet underlying_type= enum_underlying_type(min_value, max_value, is_packed); enum_tag_symbol.type.subtype()=underlying_type; // is it in the symbol table already? symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); if(s_it!=symbol_table.symbols.end()) { // Yes. symbolt &symbol=s_it->second; if(symbol.type.id()==ID_incomplete_c_enum) { // Ok, overwrite the type in the symbol table. // This gives us the members and the subtype. symbol.type=enum_tag_symbol.type; } else if(symbol.type.id()==ID_c_enum) { // We might already have the same anonymous enum, and this is // simply ok. Note that the C standard treats these as // different types. if(!base_name.empty()) { error().source_location=type.source_location(); error() << "redeclaration of enum tag" << eom; throw 0; } } else { error().source_location=source_location; error() << "use of tag that does not match previous declaration" << eom; throw 0; } } else { symbolt *new_symbol; move_symbol(enum_tag_symbol, new_symbol); } // We produce a c_enum_tag as the resulting type. type.id(ID_c_enum_tag); type.remove(ID_tag); type.set(ID_identifier, identifier); }
void ansi_c_convert_typet::read_rec(const typet &type) { if(type.id()==ID_merged_type) { forall_subtypes(it, type) read_rec(*it); } else if(type.id()==ID_signed) signed_cnt++; else if(type.id()==ID_unsigned) unsigned_cnt++; else if(type.id()==ID_ptr32) c_qualifiers.is_ptr32=true; else if(type.id()==ID_ptr64) c_qualifiers.is_ptr64=true; else if(type.id()==ID_volatile) c_qualifiers.is_volatile=true; else if(type.id()==ID_asm) { // ignore for now } else if(type.id()==ID_const) c_qualifiers.is_constant=true; else if(type.id()==ID_restricted) c_qualifiers.is_restricted=true; else if(type.id()==ID_char) char_cnt++; else if(type.id()==ID_int) int_cnt++; else if(type.id()==ID_int8) int8_cnt++; else if(type.id()==ID_int16) int16_cnt++; else if(type.id()==ID_int32) int32_cnt++; else if(type.id()==ID_int64) int64_cnt++; else if(type.id()==ID_gcc_float128) gcc_float128_cnt++; else if(type.id()==ID_gcc_int128) gcc_int128_cnt++; else if(type.id()==ID_gcc_attribute_mode) { const exprt &size_expr= static_cast<const exprt &>(type.find(ID_size)); if(size_expr.id()=="__QI__") gcc_mode_QI=true; else if(size_expr.id()=="__HI__") gcc_mode_HI=true; else if(size_expr.id()=="__SI__") gcc_mode_SI=true; else if(size_expr.id()=="__DI__") gcc_mode_DI=true; else { // we ignore without whining } } else if(type.id()==ID_bv) { bv_cnt++; const exprt &size_expr= static_cast<const exprt &>(type.find(ID_size)); mp_integer size_int; if(to_integer(size_expr, size_int)) { err_location(location); error("bit vector width has to be constant"); throw 0; } if(size_int<1 || size_int>1024) { err_location(location); error("bit vector width invalid"); throw 0; } bv_width=integer2long(size_int); } else if(type.id()==ID_short) short_cnt++; else if(type.id()==ID_long) long_cnt++; else if(type.id()==ID_double) double_cnt++; else if(type.id()==ID_float) float_cnt++; else if(type.id()==ID_bool) c_bool_cnt++; else if(type.id()==ID_proper_bool) proper_bool_cnt++; else if(type.id()==ID_complex) complex_cnt++; else if(type.id()==ID_static) c_storage_spec.is_static=true; else if(type.id()==ID_thread_local) c_storage_spec.is_thread_local=true; else if(type.id()==ID_inline) c_storage_spec.is_inline=true; else if(type.id()==ID_extern) c_storage_spec.is_extern=true; else if(type.id()==ID_typedef) c_storage_spec.is_typedef=true; else if(type.id()==ID_register) c_storage_spec.is_register=true; else if(type.id()==ID_auto) { // ignore } else if(type.id()==ID_packed) packed=true; else if(type.id()==ID_aligned) { aligned=true; // may come with size or not if(type.find(ID_size).is_nil()) alignment=exprt(ID_default); else alignment=static_cast<const exprt &>(type.find(ID_size)); } else if(type.id()==ID_transparent_union) { c_qualifiers.is_transparent_union=true; } else if(type.id()==ID_vector) vector_size=to_vector_type(type).size(); else if(type.id()==ID_void) { // we store 'void' as 'empty' typet tmp=type; tmp.id(ID_empty); other.push_back(tmp); } else other.push_back(type); }
mp_integer alignment(const typet &type, const namespacet &ns) { // is the alignment given? const exprt &given_alignment= static_cast<const exprt &>(type.find(ID_C_alignment)); if(given_alignment.is_not_nil()) { mp_integer a_int; if(!to_integer(given_alignment, a_int)) return a_int; // we trust it blindly, no matter how nonsensical } // compute default if(type.id()==ID_array) { return alignment(type.subtype(), ns); } else if(type.id()==ID_struct || type.id()==ID_union) { const struct_union_typet::componentst &components= to_struct_union_type(type).components(); mp_integer result=1; // get the max // (should really be the smallest common denominator) for(struct_union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) result=std::max(result, alignment(it->type(), ns)); return result; } else if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_fixedbv || type.id()==ID_floatbv || type.id()==ID_c_bool) { unsigned width=to_bitvector_type(type).get_width(); return width%8?width/8+1:width/8; } else if(type.id()==ID_c_enum) { return alignment(type.subtype(), ns); } else if(type.id()==ID_c_enum_tag) { return alignment(ns.follow_tag(to_c_enum_tag_type(type)), ns); } else if(type.id()==ID_pointer) { unsigned width=config.ansi_c.pointer_width; return width%8?width/8+1:width/8; } else if(type.id()==ID_symbol) return alignment(ns.follow(type), ns); return 1; }
void ansi_c_convert_typet::read_rec(const typet &type) { if(type.id()==ID_merged_type) { forall_subtypes(it, type) read_rec(*it); } else if(type.id()==ID_signed) signed_cnt++; else if(type.id()==ID_unsigned) unsigned_cnt++; else if(type.id()==ID_ptr32) c_qualifiers.is_ptr32=true; else if(type.id()==ID_ptr64) c_qualifiers.is_ptr64=true; else if(type.id()==ID_volatile) c_qualifiers.is_volatile=true; else if(type.id()==ID_asm) { // These are called 'asm labels' by GCC. // ignore for now } else if(type.id()==ID_const) c_qualifiers.is_constant=true; else if(type.id()==ID_restrict) c_qualifiers.is_restricted=true; else if(type.id()==ID_atomic) c_qualifiers.is_atomic=true; else if(type.id()==ID_atomic_type_specifier) { // this gets turned into the qualifier, uh c_qualifiers.is_atomic=true; read_rec(type.subtype()); } else if(type.id()==ID_char) char_cnt++; else if(type.id()==ID_int) int_cnt++; else if(type.id()==ID_int8) int8_cnt++; else if(type.id()==ID_int16) int16_cnt++; else if(type.id()==ID_int32) int32_cnt++; else if(type.id()==ID_int64) int64_cnt++; else if(type.id()==ID_gcc_float128) gcc_float128_cnt++; else if(type.id()==ID_gcc_int128) gcc_int128_cnt++; else if(type.id()==ID_gcc_attribute_mode) { gcc_attribute_mode=type; } else if(type.id()==ID_gcc_attribute) { } else if(type.id()==ID_msc_based) { const exprt &as_expr=static_cast<const exprt &>(static_cast<const irept &>(type)); assert(as_expr.operands().size()==1); msc_based=as_expr.op0(); } else if(type.id()==ID_custom_bv) { bv_cnt++; const exprt &size_expr= static_cast<const exprt &>(type.find(ID_size)); bv_width=size_expr; } else if(type.id()==ID_custom_floatbv) { floatbv_cnt++; const exprt &size_expr= static_cast<const exprt &>(type.find(ID_size)); const exprt &fsize_expr= static_cast<const exprt &>(type.find(ID_f)); bv_width=size_expr; fraction_width=fsize_expr; } else if(type.id()==ID_custom_fixedbv) { fixedbv_cnt++; const exprt &size_expr= static_cast<const exprt &>(type.find(ID_size)); const exprt &fsize_expr= static_cast<const exprt &>(type.find(ID_f)); bv_width=size_expr; fraction_width=fsize_expr; } else if(type.id()==ID_short) short_cnt++; else if(type.id()==ID_long) long_cnt++; else if(type.id()==ID_double) double_cnt++; else if(type.id()==ID_float) float_cnt++; else if(type.id()==ID_c_bool) c_bool_cnt++; else if(type.id()==ID_proper_bool) proper_bool_cnt++; else if(type.id()==ID_complex) complex_cnt++; else if(type.id()==ID_static) c_storage_spec.is_static=true; else if(type.id()==ID_thread_local) c_storage_spec.is_thread_local=true; else if(type.id()==ID_inline) c_storage_spec.is_inline=true; else if(type.id()==ID_extern) c_storage_spec.is_extern=true; else if(type.id()==ID_typedef) c_storage_spec.is_typedef=true; else if(type.id()==ID_register) c_storage_spec.is_register=true; else if(type.id()==ID_auto) { // ignore } else if(type.id()==ID_packed) packed=true; else if(type.id()==ID_aligned) { aligned=true; // may come with size or not if(type.find(ID_size).is_nil()) alignment=exprt(ID_default); else alignment=static_cast<const exprt &>(type.find(ID_size)); } else if(type.id()==ID_transparent_union) { c_qualifiers.is_transparent_union=true; } else if(type.id()==ID_vector) vector_size=to_vector_type(type).size(); else if(type.id()==ID_void) { // we store 'void' as 'empty' typet tmp=type; tmp.id(ID_empty); other.push_back(tmp); } else if(type.id()==ID_msc_declspec) { const exprt &as_expr= static_cast<const exprt &>(static_cast<const irept &>(type)); forall_operands(it, as_expr) { // these are symbols const irep_idt &id=it->get(ID_identifier); if(id=="thread") c_storage_spec.is_thread_local=true; else if(id=="align") { assert(it->operands().size()==1); aligned=true; alignment=it->op0(); } } } else
void c_typecheck_baset::typecheck_type(typet &type) { // we first convert, and then check { ansi_c_convert_typet ansi_c_convert_type(get_message_handler()); ansi_c_convert_type.read(type); ansi_c_convert_type.write(type); } if(type.id()==ID_already_typechecked) { // need to preserve any qualifiers c_qualifierst c_qualifiers(type); c_qualifiers+=c_qualifierst(type.subtype()); bool packed=type.get_bool(ID_C_packed); exprt alignment=static_cast<const exprt &>(type.find(ID_C_alignment)); irept _typedef=type.find(ID_C_typedef); type=type.subtype(); c_qualifiers.write(type); if(packed) type.set(ID_C_packed, true); if(alignment.is_not_nil()) type.add(ID_C_alignment, alignment); if(_typedef.is_not_nil()) type.add(ID_C_typedef, _typedef); return; // done } // do we have alignment? if(type.find(ID_C_alignment).is_not_nil()) { exprt &alignment=static_cast<exprt &>(type.add(ID_C_alignment)); if(alignment.id()!=ID_default) { typecheck_expr(alignment); make_constant(alignment); } } if(type.id()==ID_code) typecheck_code_type(to_code_type(type)); else if(type.id()==ID_array) typecheck_array_type(to_array_type(type)); else if(type.id()==ID_pointer) typecheck_type(type.subtype()); else if(type.id()==ID_struct || type.id()==ID_union) typecheck_compound_type(to_struct_union_type(type)); else if(type.id()==ID_c_enum) typecheck_c_enum_type(type); else if(type.id()==ID_c_enum_tag) typecheck_c_enum_tag_type(to_c_enum_tag_type(type)); else if(type.id()==ID_c_bit_field) typecheck_c_bit_field_type(to_c_bit_field_type(type)); else if(type.id()==ID_typeof) typecheck_typeof_type(type); else if(type.id()==ID_symbol) typecheck_symbol_type(type); else if(type.id()==ID_vector) typecheck_vector_type(to_vector_type(type)); else if(type.id()==ID_custom_unsignedbv || type.id()==ID_custom_signedbv || type.id()==ID_custom_floatbv || type.id()==ID_custom_fixedbv) typecheck_custom_type(type); else if(type.id()==ID_gcc_attribute_mode) { // get that mode irep_idt mode=type.get(ID_size); // A list of all modes ist at // http://www.delorie.com/gnu/docs/gcc/gccint_53.html typecheck_type(type.subtype()); typet underlying_type=type.subtype(); // gcc allows this, but clang doesn't; it's a compiler hint only, // but we'll try to interpret it the GCC way if(underlying_type.id()==ID_c_enum_tag) { underlying_type= follow_tag(to_c_enum_tag_type(underlying_type)).subtype(); assert(underlying_type.id()==ID_signedbv || underlying_type.id()==ID_unsignedbv); } if(underlying_type.id()==ID_signedbv || underlying_type.id()==ID_unsignedbv) { bool is_signed=underlying_type.id()==ID_signedbv; typet result; if(mode=="__QI__") // 8 bits result=is_signed?signed_char_type():unsigned_char_type(); else if(mode=="__byte__") // 8 bits result=is_signed?signed_char_type():unsigned_char_type(); else if(mode=="__HI__") // 16 bits result=is_signed?signed_short_int_type():unsigned_short_int_type(); else if(mode=="__SI__") // 32 bits result=is_signed?signed_int_type():unsigned_int_type(); else if(mode=="__word__") // long int, we think result=is_signed?signed_long_int_type():unsigned_long_int_type(); else if(mode=="__pointer__") // we think this is size_t/ssize_t result=is_signed?signed_size_type():size_type(); else if(mode=="__DI__") // 64 bits { if(config.ansi_c.long_int_width==64) result=is_signed?signed_long_int_type():unsigned_long_int_type(); else { assert(config.ansi_c.long_long_int_width==64); result= is_signed?signed_long_long_int_type():unsigned_long_long_int_type(); } } else if(mode=="__TI__") // 128 bits result=is_signed?gcc_signed_int128_type():gcc_unsigned_int128_type(); else if(mode=="__V2SI__") // vector of 2 ints, deprecated by gcc result= vector_typet( is_signed?signed_int_type():unsigned_int_type(), from_integer(2, size_type())); else if(mode=="__V4SI__") // vector of 4 ints, deprecated by gcc result= vector_typet( is_signed?signed_int_type():unsigned_int_type(), from_integer(4, size_type())); else // give up, just use subtype result=type.subtype(); // save the location result.add_source_location()=type.source_location(); if(type.subtype().id()==ID_c_enum_tag) { const irep_idt &tag_name= to_c_enum_tag_type(type.subtype()).get_identifier(); symbol_tablet::symbolst::iterator entry= symbol_table.symbols.find(tag_name); assert(entry!=symbol_table.symbols.end()); entry->second.type.subtype()=result; } type=result; } else if(underlying_type.id()==ID_floatbv) { typet result; if(mode=="__SF__") // 32 bits result=float_type(); else if(mode=="__DF__") // 64 bits result=double_type(); else if(mode=="__TF__") // 128 bits result=gcc_float128_type(); else if(mode=="__V2SF__") // vector of 2 floats, deprecated by gcc result=vector_typet(float_type(), from_integer(2, size_type())); else if(mode=="__V2DF__") // vector of 2 doubles, deprecated by gcc result=vector_typet(double_type(), from_integer(2, size_type())); else if(mode=="__V4SF__") // vector of 4 floats, deprecated by gcc result=vector_typet(float_type(), from_integer(4, size_type())); else if(mode=="__V4DF__") // vector of 4 doubles, deprecated by gcc result=vector_typet(double_type(), from_integer(4, size_type())); else // give up, just use subtype result=type.subtype(); // save the location result.add_source_location()=type.source_location(); type=result; } else if(underlying_type.id()==ID_complex) { // gcc allows this, but clang doesn't -- see enums above typet result; if(mode=="__SC__") // 32 bits result=float_type(); else if(mode=="__DC__") // 64 bits result=double_type(); else if(mode=="__TC__") // 128 bits result=gcc_float128_type(); else // give up, just use subtype result=type.subtype(); // save the location result.add_source_location()=type.source_location(); type=complex_typet(result); } else { error().source_location=type.source_location(); error() << "attribute mode `" << mode << "' applied to inappropriate type `" << to_string(type) << "'" << eom; throw 0; } } // do a mild bit of rule checking if(type.get_bool(ID_C_restricted) && type.id()!=ID_pointer && type.id()!=ID_array) { error().source_location=type.source_location(); error() << "only a pointer can be 'restrict'" << eom; throw 0; } }