void c_typecheck_baset::typecheck_c_bit_field_type(typet &type) { typecheck_type(type.subtype()); exprt &width_expr=static_cast<exprt &>(type.add(ID_size)); typecheck_expr(width_expr); make_constant_index(width_expr); mp_integer i; if(to_integer(width_expr, i)) { err_location(type); throw "failed to convert bit field width"; } if(i<0) { err_location(type); throw "bit field width is negative"; } const typet &base_type=follow(type.subtype()); if(base_type.id()==ID_bool) { if(i>1) { err_location(type); throw "bit field width too large"; } // We don't use bool, as it's really a byte long. type.id(ID_unsignedbv); type.set(ID_width, integer2long(i)); } else if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv || base_type.id()==ID_c_enum) { unsigned width=base_type.get_int(ID_width); if(i>width) { err_location(type); throw "bit field width too large"; } typet tmp(base_type); type.swap(tmp); type.set(ID_width, integer2string(i)); } else { err_location(type); str << "bit field with non-integer type: " << to_string(base_type); throw 0; } }
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 jsil_typecheckt::typecheck_non_type_symbol(symbolt &symbol) { assert(!symbol.is_type); // Using is_extern to check if symbol was already typechecked if(symbol.is_extern) return; if(symbol.value.id()!="no-body-just-yet") symbol.is_extern=true; proc_name=symbol.name; typecheck_type(symbol.type); if(symbol.value.id()==ID_code) typecheck_code(to_code(symbol.value)); else if(symbol.name=="eval") { // No code for eval. Do nothing } else if(symbol.value.id()=="no-body-just-yet") { // Do nothing } else throw "Non type symbol value expected code, but got "+ symbol.value.pretty(); }
void c_typecheck_baset::typecheck_declaration( ansi_c_declarationt &declaration) { if(declaration.get_is_static_assert()) { assert(declaration.operands().size()==2); typecheck_expr(declaration.op0()); typecheck_expr(declaration.op1()); } else { // get storage spec c_storage_spect c_storage_spec(declaration.type()); declaration.set_is_inline(c_storage_spec.is_inline); declaration.set_is_static(c_storage_spec.is_static); declaration.set_is_extern(c_storage_spec.is_extern); declaration.set_is_thread_local(c_storage_spec.is_thread_local); declaration.set_is_register(c_storage_spec.is_register); declaration.set_is_typedef(c_storage_spec.is_typedef); // first typecheck the type of the declaration typecheck_type(declaration.type()); // mark as 'already typechecked' make_already_typechecked(declaration.type()); // Now do declarators, if any. for(ansi_c_declarationt::declaratorst::iterator d_it=declaration.declarators().begin(); d_it!=declaration.declarators().end(); d_it++) { symbolt symbol; declaration.to_symbol(*d_it, symbol); // now check other half of type typecheck_type(symbol.type); typecheck_symbol(symbol); } } }
void c_typecheck_baset::typecheck_array_type(array_typet &type) { exprt &size=type.size(); locationt location=size.find_location(); // check subtype typecheck_type(type.subtype()); // we don't allow void as subtype if(follow(type.subtype()).id()==ID_empty) { err_location(type); str << "array of voids"; throw 0; } // check size, if any if(size.is_not_nil()) { typecheck_expr(size); make_index_type(size); // The size need not be a constant! // We simplify it, for the benefit of array initialisation. exprt tmp_size=size; simplify(tmp_size, *this); if(tmp_size.is_constant()) { mp_integer s; if(to_integer(tmp_size, s)) { err_location(location); str << "failed to convert constant: " << tmp_size.pretty(); throw 0; } if(s<0) { err_location(location); str << "array size must not be negative, " "but got " << s; throw 0; } size=tmp_size; } else if(tmp_size.id()==ID_infinity) size=tmp_size; } }
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; } }
void java_bytecode_typecheckt::typecheck_type(typet &type) { if(type.id()==ID_symbol) { irep_idt identifier=to_symbol_type(type).get_identifier(); symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(identifier); // must exist already in the symbol table if(s_it==symbol_table.symbols.end()) { error() << "failed to find type symbol "<< identifier << eom; throw 0; } assert(s_it->second.is_type); } else if(type.id()==ID_pointer) { typecheck_type(type.subtype()); } else if(type.id()==ID_array) { typecheck_type(type.subtype()); typecheck_expr(to_array_type(type).size()); } 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(code_typet::parameterst::iterator it=parameters.begin(); it!=parameters.end(); it++) typecheck_type(it->type()); } }
void cpp_typecheckt::convert_non_template_declaration( cpp_declarationt &declaration) { assert(!declaration.is_template()); // we first check if this is a typedef typet &declaration_type=declaration.type(); bool is_typedef=declaration.is_typedef(); declaration.name_anon_struct_union(); typecheck_type(declaration_type); // Elaborate any class template instance _unless_ we do a typedef. // These are only elaborated on usage! if(!is_typedef) elaborate_class_template(declaration_type); // Special treatment for anonymous unions if(declaration.declarators().empty() && follow(declaration.type()).get_bool(ID_C_is_anonymous)) { typet final_type=follow(declaration.type()); if(final_type.id()!=ID_union) { error().source_location=final_type.source_location(); error() << "top-level declaration does not declare anything" << eom; throw 0; } codet dummy; convert_anonymous_union(declaration, dummy); } // do the declarators (optional) Forall_cpp_declarators(it, declaration) { // copy the declarator (we destroy the original) cpp_declaratort declarator=*it; cpp_declarator_convertert cpp_declarator_converter(*this); cpp_declarator_converter.is_typedef=is_typedef; symbolt &symbol=cpp_declarator_converter.convert( declaration_type, declaration.storage_spec(), declaration.member_spec(), declarator); // any template instance to remember? if(declaration.find(ID_C_template).is_not_nil()) { symbol.type.set(ID_C_template, declaration.find(ID_C_template)); symbol.type.set(ID_C_template_arguments, declaration.find(ID_C_template_arguments)); } // replace declarator by symbol expression exprt tmp=cpp_symbol_expr(symbol); it->swap(tmp); // is there a constructor to be called for the declarator? if(symbol.is_lvalue && declarator.init_args().has_operands()) { symbol.value= cpp_constructor( symbol.location, cpp_symbol_expr(symbol), declarator.init_args().operands()); } }
void java_bytecode_typecheckt::typecheck_type_symbol(symbolt &symbol) { assert(symbol.is_type); typecheck_type(symbol.type); }
void c_typecheck_baset::typecheck_compound_body( struct_union_typet &type) { struct_union_typet::componentst &components=type.components(); struct_union_typet::componentst old_components; old_components.swap(components); // We get these as declarations! for(auto &decl : old_components) { // the arguments are member declarations or static assertions assert(decl.id()==ID_declaration); ansi_c_declarationt &declaration= to_ansi_c_declaration(static_cast<exprt &>(decl)); if(declaration.get_is_static_assert()) { struct_union_typet::componentt new_component; new_component.id(ID_static_assert); new_component.add_source_location()=declaration.source_location(); new_component.operands().swap(declaration.operands()); assert(new_component.operands().size()==2); components.push_back(new_component); } else { // do first half of type typecheck_type(declaration.type()); make_already_typechecked(declaration.type()); for(const auto &declarator : declaration.declarators()) { struct_union_typet::componentt new_component; new_component.add_source_location()= declarator.source_location(); new_component.set(ID_name, declarator.get_base_name()); new_component.set(ID_pretty_name, declarator.get_base_name()); new_component.type()=declaration.full_type(declarator); typecheck_type(new_component.type()); if(!is_complete_type(new_component.type()) && (new_component.type().id()!=ID_array || !to_array_type(new_component.type()).is_incomplete())) { error().source_location=new_component.type().source_location(); error() << "incomplete type not permitted here" << eom; throw 0; } components.push_back(new_component); } } } unsigned anon_member_counter=0; // scan for anonymous members, and name them for(auto &member : components) { if(member.get_name()!=irep_idt()) continue; member.set_name("$anon"+std::to_string(anon_member_counter++)); member.set_anonymous(true); } // scan for duplicate members { std::unordered_set<irep_idt, irep_id_hash> members; for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(!members.insert(it->get_name()).second) { error().source_location=it->source_location(); error() << "duplicate member '" << it->get_name() << '\'' << eom; throw 0; } } } // We allow an incomplete (C99) array as _last_ member! // Zero-length is allowed everywhere. if(type.id()==ID_struct || type.id()==ID_union) { for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { typet &c_type=it->type(); if(c_type.id()==ID_array && to_array_type(c_type).is_incomplete()) { // needs to be last member if(type.id()==ID_struct && it!=--components.end()) { error().source_location=it->source_location(); error() << "flexible struct member must be last member" << eom; throw 0; } // make it zero-length c_type.id(ID_array); c_type.set(ID_size, from_integer(0, index_type())); } } } // We may add some minimal padding inside and at // the end of structs and // as additional member for unions. if(type.id()==ID_struct) add_padding(to_struct_type(type), *this); else if(type.id()==ID_union) add_padding(to_union_type(type), *this); // Now remove zero-width bit-fields, these are just // for adjusting alignment. for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // blank { if(it->type().id()==ID_c_bit_field && to_c_bit_field_type(it->type()).get_width()==0) it=components.erase(it); else it++; } // finally, check _Static_assert inside the compound for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // no it++ { if(it->id()==ID_static_assert) { assert(it->operands().size()==2); exprt &assertion=it->op0(); typecheck_expr(assertion); typecheck_expr(it->op1()); assertion.make_typecast(bool_typet()); make_constant(assertion); if(assertion.is_false()) { error().source_location=it->source_location(); error() << "failed _Static_assert" << eom; throw 0; } else if(!assertion.is_true()) { // should warn/complain } it=components.erase(it); } else it++; } }
void c_typecheck_baset::typecheck_vector_type(vector_typet &type) { exprt &size=type.size(); source_locationt source_location=size.find_source_location(); typecheck_expr(size); typet &subtype=type.subtype(); typecheck_type(subtype); // we are willing to combine 'vector' with various // other types, but not everything! if(subtype.id()!=ID_signedbv && subtype.id()!=ID_unsignedbv && subtype.id()!=ID_floatbv && subtype.id()!=ID_fixedbv) { error().source_location=source_location; error() << "cannot make a vector of subtype " << to_string(subtype) << eom; throw 0; } make_constant_index(size); mp_integer s; if(to_integer(size, s)) { error().source_location=source_location; error() << "failed to convert constant: " << size.pretty() << eom; throw 0; } if(s<=0) { error().source_location=source_location; error() << "vector size must be positive, " "but got " << s << eom; throw 0; } // the subtype must have constant size exprt size_expr=c_sizeof(type.subtype(), *this); simplify(size_expr, *this); mp_integer sub_size; if(to_integer(size_expr, sub_size)) { error().source_location=source_location; error() << "failed to determine size of vector base type `" << to_string(type.subtype()) << "'" << eom; throw 0; } if(sub_size==0) { error().source_location=source_location; error() << "type had size 0: `" << to_string(type.subtype()) << "'" << eom; throw 0; } // adjust by width of base type if(s%sub_size!=0) { error().source_location=source_location; error() << "vector size (" << s << ") expected to be multiple of base type size (" << sub_size << ")" << eom; throw 0; } s/=sub_size; type.size()=from_integer(s, signed_size_type()); }
void c_typecheck_baset::typecheck_array_type(array_typet &type) { exprt &size=type.size(); source_locationt source_location=size.find_source_location(); // check subtype typecheck_type(type.subtype()); // we don't allow void as subtype if(follow(type.subtype()).id()==ID_empty) { error().source_location=type.source_location(); error() << "array of voids" << eom; throw 0; } // check size, if any if(size.is_not_nil()) { typecheck_expr(size); make_index_type(size); // The size need not be a constant! // We simplify it, for the benefit of array initialisation. exprt tmp_size=size; add_rounding_mode(tmp_size); simplify(tmp_size, *this); if(tmp_size.is_constant()) { mp_integer s; if(to_integer(tmp_size, s)) { error().source_location=source_location; error() << "failed to convert constant: " << tmp_size.pretty() << eom; throw 0; } if(s<0) { error().source_location=source_location; error() << "array size must not be negative, " "but got " << s << eom; throw 0; } size=tmp_size; } else if(tmp_size.id()==ID_infinity) { size=tmp_size; } else if(tmp_size.id()==ID_symbol && tmp_size.type().get_bool(ID_C_constant)) { // We allow a constant variable as array size, assuming // it won't change. // This criterion can be tricked: // Of course we can modify a 'const' symbol, e.g., // using a pointer type cast. Interestingly, // at least gcc 4.2.1 makes the very same mistake! size=tmp_size; } else { // not a constant and not infinity assert(current_symbol_id!=irep_idt()); const symbolt &base_symbol=lookup(current_symbol_id); // Need to pull out! We insert new symbol. source_locationt source_location=size.find_source_location(); unsigned count=0; irep_idt temp_identifier; std::string suffix; do { suffix="$array_size"+std::to_string(count); temp_identifier=id2string(base_symbol.name)+suffix; count++; } while(symbol_table.symbols.find(temp_identifier)!= symbol_table.symbols.end()); // add the symbol to symbol table auxiliary_symbolt new_symbol; new_symbol.name=temp_identifier; new_symbol.pretty_name=id2string(base_symbol.pretty_name)+suffix; new_symbol.base_name=id2string(base_symbol.base_name)+suffix; new_symbol.type=size.type(); new_symbol.type.set(ID_C_constant, true); new_symbol.is_type=false; new_symbol.is_static_lifetime=false; new_symbol.value.make_nil(); new_symbol.location=source_location; symbol_table.add(new_symbol); // produce the code that declares and initializes the symbol symbol_exprt symbol_expr; symbol_expr.set_identifier(temp_identifier); symbol_expr.type()=new_symbol.type; code_declt declaration(symbol_expr); declaration.add_source_location()=source_location; code_assignt assignment; assignment.lhs()=symbol_expr; assignment.rhs()=size; assignment.add_source_location()=source_location; // store the code clean_code.push_back(declaration); clean_code.push_back(assignment); // fix type size=symbol_expr; } } }
void c_typecheck_baset::typecheck_code_type(code_typet &type) { // the return type is still 'subtype()' type.return_type()=type.subtype(); type.remove_subtype(); code_typet::parameterst ¶meters=type.parameters(); // if we don't have any parameters, we assume it's (...) if(parameters.empty()) { type.make_ellipsis(); } else // we do have parameters { // is the last one ellipsis? if(type.parameters().back().id()==ID_ellipsis) { type.make_ellipsis(); type.parameters().pop_back(); } parameter_map.clear(); for(auto ¶m : type.parameters()) { // turn the declarations into parameters if(param.id()==ID_declaration) { ansi_c_declarationt &declaration= to_ansi_c_declaration(param); code_typet::parametert parameter; // first fix type typet &type=parameter.type(); type=declaration.full_type(declaration.declarator()); std::list<codet> tmp_clean_code; tmp_clean_code.swap(clean_code); // ignore side-effects typecheck_type(type); tmp_clean_code.swap(clean_code); adjust_function_parameter(type); // adjust the identifier irep_idt identifier=declaration.declarator().get_name(); // abstract or not? if(identifier==irep_idt()) { // abstract parameter.add_source_location()=declaration.type().source_location(); } else { // make visible now, later parameters might use it parameter_map[identifier]=type; parameter.set_base_name(declaration.declarator().get_base_name()); parameter.add_source_location()= declaration.declarator().source_location(); } // put the parameter in place of the declaration param.swap(parameter); } } parameter_map.clear(); if(parameters.size()==1 && follow(parameters[0].type()).id()==ID_empty) { // if we just have one parameter of type void, remove it parameters.clear(); } } typecheck_type(type.return_type()); // 6.7.6.3: // "A function declarator shall not specify a return type that // is a function type or an array type." const typet &return_type=follow(type.return_type()); if(return_type.id()==ID_array) { error().source_location=type.source_location(); error() << "function must not return array" << eom; throw 0; } if(return_type.id()==ID_code) { error().source_location=type.source_location(); error() << "function must not return function type" << eom; throw 0; } }
void cpp_typecheckt::typecheck_compound_declarator( const symbolt &symbol, const cpp_declarationt &declaration, cpp_declaratort &declarator, struct_typet::componentst &components, const irep_idt &access, bool is_static, bool is_typedef, bool is_mutable) { bool is_cast_operator= declaration.type().id()=="cpp-cast-operator"; if(is_cast_operator) { assert(declarator.name().get_sub().size()==2 && declarator.name().get_sub().front().id()==ID_operator); typet type=static_cast<typet &>(declarator.name().get_sub()[1]); declarator.type().subtype()=type; irept name(ID_name); name.set(ID_identifier, "("+cpp_type2name(type)+")"); declarator.name().get_sub().back().swap(name); } typet final_type= declarator.merge_type(declaration.type()); // this triggers template elaboration elaborate_class_template(final_type); typecheck_type(final_type); cpp_namet cpp_name; cpp_name.swap(declarator.name()); irep_idt base_name; if(cpp_name.is_nil()) { // Yes, there can be members without name. base_name=irep_idt(); } else if(cpp_name.is_simple_name()) { base_name=cpp_name.get_base_name(); } else { err_location(cpp_name.location()); str << "declarator in compound needs to be simple name"; throw 0; } bool is_method=!is_typedef && final_type.id()==ID_code; bool is_constructor=declaration.is_constructor(); bool is_destructor=declaration.is_destructor(); bool is_virtual=declaration.member_spec().is_virtual(); bool is_explicit=declaration.member_spec().is_explicit(); bool is_inline=declaration.member_spec().is_inline(); final_type.set(ID_C_member_name, symbol.name); // first do some sanity checks if(is_virtual && !is_method) { err_location(cpp_name.location()); str << "only methods can be virtual"; throw 0; } if(is_inline && !is_method) { err_location(cpp_name.location()); str << "only methods can be inlined"; throw 0; } if(is_virtual && is_static) { err_location(cpp_name.location()); str << "static methods cannot be virtual"; throw 0; } if(is_cast_operator && is_static) { err_location(cpp_name.location()); str << "cast operators cannot be static`"; throw 0; } if(is_constructor && is_virtual) { err_location(cpp_name.location()); str << "constructors cannot be virtual"; throw 0; } if(!is_constructor && is_explicit) { err_location(cpp_name.location()); str << "only constructors can be explicit"; throw 0; } if(is_constructor && base_name!=id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "member function must return a value or void"; throw 0; } if(is_destructor && base_name!="~"+id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "destructor with wrong name"; throw 0; } // now do actual work struct_typet::componentt component; irep_idt identifier= language_prefix+ cpp_scopes.current_scope().prefix+ id2string(base_name); component.set(ID_name, identifier); component.type()=final_type; component.set(ID_access, access); component.set(ID_base_name, base_name); component.set(ID_pretty_name, base_name); component.location()=cpp_name.location(); if(cpp_name.is_operator()) { component.set("is_operator", true); component.type().set("#is_operator", true); } if(is_cast_operator) component.set("is_cast_operator", true); if(declaration.member_spec().is_explicit()) component.set("is_explicit", true); typet &method_qualifier= (typet &)declarator.add("method_qualifier"); if(is_static) { component.set(ID_is_static, true); component.type().set("#is_static", true); } if(is_typedef) component.set("is_type", true); if(is_mutable) component.set("is_mutable", true); exprt &value=declarator.value(); irept &initializers=declarator.member_initializers(); if(is_method) { component.set(ID_is_inline, declaration.member_spec().is_inline()); // the 'virtual' name of the function std::string virtual_name= component.get_string(ID_base_name)+ id2string( function_identifier(static_cast<const typet &>(component.find(ID_type)))); if(method_qualifier.id()==ID_const) virtual_name += "$const"; if(component.type().get(ID_return_type) == ID_destructor) virtual_name= "@dtor"; // The method may be virtual implicitly. std::set<irep_idt> virtual_bases; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_bool("is_virtual")) { if(it->get("virtual_name")==virtual_name) { is_virtual=true; const code_typet& code_type = to_code_type(it->type()); assert(code_type.arguments().size()>0); const typet& pointer_type = code_type.arguments()[0].type(); assert(pointer_type.id() == ID_pointer); virtual_bases.insert(pointer_type.subtype().get(ID_identifier)); } } } if(!is_virtual) { typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); if(!value.is_nil() && !is_static) { err_location(cpp_name.location()); str << "no initialization allowed here"; throw 0; } } else // virtual { component.type().set("#is_virtual", true); component.type().set("#virtual_name",virtual_name); // Check if it is a pure virtual method if(is_virtual) { if(value.is_not_nil() && value.id() == ID_constant) { mp_integer i; to_integer(value, i); if(i!=0) { err_location(declarator.name().location()); str << "expected 0 to mark pure virtual method, got " << i; } component.set("is_pure_virtual", true); value.make_nil(); } } typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); // get the virtual-table symbol type irep_idt vt_name = "virtual_table::"+symbol.name.as_string(); contextt::symbolst::iterator vtit = context.symbols.find(vt_name); if(vtit == context.symbols.end()) { // first time: create a virtual-table symbol type symbolt vt_symb_type; vt_symb_type.name= vt_name; vt_symb_type.base_name="virtual_table::"+symbol.base_name.as_string(); vt_symb_type.pretty_name = vt_symb_type.base_name; vt_symb_type.mode=ID_cpp; vt_symb_type.module=module; vt_symb_type.location=symbol.location; vt_symb_type.type = struct_typet(); vt_symb_type.type.set(ID_name, vt_symb_type.name); vt_symb_type.is_type = true; bool failed = context.move(vt_symb_type); assert(!failed); vtit = context.symbols.find(vt_name); // add a virtual-table pointer struct_typet::componentt compo; compo.type() = pointer_typet(symbol_typet(vt_name)); compo.set_name(symbol.name.as_string() +"::@vtable_pointer"); compo.set(ID_base_name, "@vtable_pointer"); compo.set(ID_pretty_name, symbol.base_name.as_string() +"@vtable_pointer"); compo.set("is_vtptr", true); compo.set(ID_access, ID_public); components.push_back(compo); put_compound_into_scope(compo); } assert(vtit->second.type.id()==ID_struct); struct_typet &virtual_table= to_struct_type(vtit->second.type); component.set("virtual_name", virtual_name); component.set("is_virtual", is_virtual); // add an entry to the virtual table struct_typet::componentt vt_entry; vt_entry.type() = pointer_typet(component.type()); vt_entry.set_name(vtit->first.as_string()+"::"+virtual_name); vt_entry.set(ID_base_name, virtual_name); vt_entry.set(ID_pretty_name, virtual_name); vt_entry.set(ID_access, ID_public); vt_entry.location() = symbol.location; virtual_table.components().push_back(vt_entry); // take care of overloading while(!virtual_bases.empty()) { irep_idt virtual_base = *virtual_bases.begin(); // a new function that does 'late casting' of the 'this' parameter symbolt func_symb; func_symb.name=component.get_name().as_string() + "::" +virtual_base.as_string(); func_symb.base_name=component.get(ID_base_name); func_symb.pretty_name = component.get(ID_base_name); func_symb.mode=ID_cpp; func_symb.module=module; func_symb.location=component.location(); func_symb.type=component.type(); // change the type of the 'this' pointer code_typet& code_type = to_code_type(func_symb.type); code_typet::argumentt& arg= code_type.arguments().front(); arg.type().subtype().set(ID_identifier, virtual_base); // create symbols for the arguments code_typet::argumentst& args = code_type.arguments(); for(unsigned i=0; i<args.size(); i++) { code_typet::argumentt& arg = args[i]; irep_idt base_name = arg.get_base_name(); if(base_name==irep_idt()) base_name="arg"+i2string(i); symbolt arg_symb; arg_symb.name = func_symb.name.as_string() + "::"+ base_name.as_string(); arg_symb.base_name = base_name; arg_symb.pretty_name = base_name; arg_symb.mode=ID_cpp; arg_symb.location=func_symb.location; arg_symb.type = arg.type(); arg.set(ID_C_identifier, arg_symb.name); // add the argument to the symbol table bool failed = context.move(arg_symb); assert(!failed); } // do the body of the function typecast_exprt late_cast(to_code_type(component.type()).arguments()[0].type()); late_cast.op0()= symbol_expr(namespacet(context).lookup( args[0].get(ID_C_identifier))); if(code_type.return_type().id()!=ID_empty && code_type.return_type().id()!=ID_destructor) { side_effect_expr_function_callt expr_call; expr_call.function() = symbol_exprt(component.get_name(),component.type()); expr_call.type() = to_code_type(component.type()).return_type(); expr_call.arguments().reserve(args.size()); expr_call.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { expr_call.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } code_returnt code_return; code_return.return_value() = expr_call; func_symb.value = code_return; } else { code_function_callt code_func; code_func.function() = symbol_exprt(component.get_name(),component.type()); code_func.arguments().reserve(args.size()); code_func.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { code_func.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } func_symb.value = code_func; } // add this new function to the list of components struct_typet::componentt new_compo = component; new_compo.type() = func_symb.type; new_compo.set_name(func_symb.name); components.push_back(new_compo); // add the function to the symbol table { bool failed = context.move(func_symb); assert(!failed); } // next base virtual_bases.erase(virtual_bases.begin()); } } } if(is_static && !is_method) // static non-method member { // add as global variable to context symbolt static_symbol; static_symbol.mode=symbol.mode; static_symbol.name=identifier; static_symbol.type=component.type(); static_symbol.base_name=component.get(ID_base_name); static_symbol.lvalue=true; static_symbol.static_lifetime=true; static_symbol.location=cpp_name.location(); static_symbol.is_extern=true; // TODO: not sure about this: should be defined separately! dynamic_initializations.push_back(static_symbol.name); symbolt *new_symbol; if(context.move(static_symbol, new_symbol)) { err_location(cpp_name.location()); str << "redeclaration of static member `" << static_symbol.base_name.as_string() << "'"; throw 0; } if(value.is_not_nil()) { if(cpp_is_pod(new_symbol->type)) { new_symbol->value.swap(value); c_typecheck_baset::do_initializer(*new_symbol); // these are macros if they are PODs and come with a (constant) value if(new_symbol->type.get_bool(ID_C_constant)) { simplify(new_symbol->value, *this); new_symbol->is_macro=true; } } else { symbol_exprt symexpr; symexpr.set_identifier(new_symbol->name); exprt::operandst ops; ops.push_back(value); codet defcode = cpp_constructor(locationt(), symexpr, ops); new_symbol->value.swap(defcode); } } } // array members must have fixed size check_fixed_size_array(component.type()); put_compound_into_scope(component); components.push_back(component); }
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()); }
cpp_template_args_tct cpp_typecheckt::typecheck_template_args( const source_locationt &source_location, const symbolt &template_symbol, const cpp_template_args_non_tct &template_args) { // old stuff assert(template_args.id()!=ID_already_typechecked); assert(template_symbol.type.get_bool(ID_is_template)); const template_typet &template_type= to_cpp_declaration(template_symbol.type).template_type(); // bad re-cast, but better than copying the args one by one cpp_template_args_tct result= (const cpp_template_args_tct &)(template_args); cpp_template_args_tct::argumentst &args= result.arguments(); const template_typet::template_parameterst ¶meters= template_type.template_parameters(); if(parameters.size()<args.size()) { err_location(source_location); str << "too many template arguments (expected " << parameters.size() << ", but got " << args.size() << ")"; throw 0; } // we will modify the template map template_mapt old_template_map; old_template_map=template_map; // check for default arguments for(unsigned i=0; i<parameters.size(); i++) { const template_parametert ¶meter=parameters[i]; cpp_save_scopet cpp_saved_scope(cpp_scopes); if(i>=args.size()) { // Check for default argument for the parameter. // These may depend on previous arguments. if(!parameter.has_default_argument()) { err_location(source_location); str << "not enough template arguments (expected " << parameters.size() << ", but got " << args.size() << ")"; throw 0; } args.push_back(parameter.default_argument()); // these need to be typechecked in the scope of the template, // not in the current scope! cpp_idt *template_scope=cpp_scopes.id_map[template_symbol.name]; assert(template_scope!=NULL); cpp_scopes.go_to(*template_scope); } assert(i<args.size()); exprt &arg=args[i]; if(parameter.id()==ID_type) { if(arg.id()==ID_type) { typecheck_type(arg.type()); } else if(arg.id()=="ambiguous") { typecheck_type(arg.type()); typet t=arg.type(); arg=exprt(ID_type, t); } else { err_location(arg); str << "expected type, but got expression"; throw 0; } } else // expression { if(arg.id()==ID_type) { err_location(arg); str << "expected expression, but got type"; throw 0; } else if(arg.id()=="ambiguous") { exprt e; e.swap(arg.type()); arg.swap(e); } typet type=parameter.type(); // First check the parameter type (might have ealier // type parameters in it). Needs to be checked in scope // of template. { cpp_save_scopet cpp_saved_scope(cpp_scopes); cpp_idt *template_scope=cpp_scopes.id_map[template_symbol.name]; assert(template_scope!=NULL); cpp_scopes.go_to(*template_scope); typecheck_type(type); } // Now check the argument to match that. typecheck_expr(arg); simplify(arg, *this); implicit_typecast(arg, type); } // Set right away -- this is for the benefit of default // arguments and later parameters whose type might // depend on an earlier parameter. template_map.set(parameter, arg); } // restore template map template_map.swap(old_template_map); // now the numbers should match assert(args.size()==parameters.size()); return result; }
void c_typecheck_baset::typecheck_code_type(code_typet &type) { code_typet::parameterst ¶meters=type.parameters(); // if we don't have any parameters, we assume it's (...) if(parameters.empty()) { type.make_ellipsis(); } else { // we do have parameters parameter_map.clear(); for(unsigned i=0; i<type.parameters().size(); i++) { code_typet::parametert ¶meter=type.parameters()[i]; // first fix type typet &type=parameter.type(); typecheck_type(type); adjust_function_parameter(type); // adjust the identifier irep_idt identifier=parameter.get_identifier(); if(identifier!=irep_idt()) { identifier=add_language_prefix(identifier); id_replace_mapt::const_iterator m_it=id_replace_map.find(identifier); if(m_it!=id_replace_map.end()) identifier=m_it->second; parameter.set_identifier(identifier); // make visible now, later parameters might use it parameter_map[identifier]=type; } } parameter_map.clear(); if(parameters.size()==1 && follow(parameters[0].type()).id()==ID_empty) { // if we just have one parameter of type void, remove it parameters.clear(); } } typecheck_type(type.return_type()); // 6.7.6.3: // "A function declarator shall not specify a return type that // is a function type or an array type." const typet &return_type=follow(type.return_type()); if(return_type.id()==ID_array) { err_location(type); throw "function must not return array"; } if(return_type.id()==ID_code) { err_location(type); throw "function must not return function type"; } }
void c_typecheck_baset::typecheck_compound_type(struct_union_typet &type) { struct_union_typet::componentst &components=type.components(); // mark bit-fields for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) if(it->type().id()==ID_c_bitfield) { it->set_is_bit_field(true); typet tmp=it->type().subtype(); typecheck_type(tmp); it->set_bit_field_type(tmp); } // check subtypes for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) typecheck_type(it->type()); unsigned anon_member_counter=0; // scan for anonymous members, and name them for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(it->get_name()!=irep_idt()) continue; it->set_name("$anon"+i2string(anon_member_counter++)); it->set_anonymous(true); } // scan for duplicate members { hash_set_cont<irep_idt, irep_id_hash> members; for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(!members.insert(it->get_name()).second) { // we do nothing (as gcc won't complain) } } } // We allow an incomplete (C99) array as _last_ member! // Zero-length is allowed everywhere. if(type.id()==ID_struct) { for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { typet &type=it->type(); if(type.id()==ID_array && to_array_type(type).is_incomplete()) { // needs to be last member if(it!=--components.end()) { err_location(*it); throw "flexible struct member must be last member"; } // make it zero-length type.id(ID_array); type.set(ID_size, gen_zero(index_type())); } } } // we may add some minimal padding inside structs (not unions) // unless there is an attribute that says that the struct is // 'packed' if(type.id()==ID_struct) add_padding(to_struct_type(type), *this); // finally, check _Static_assert inside the compound for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // no it++ { if(it->id()==ID_code && it->get(ID_statement)==ID_static_assert) { assert(it->operands().size()==2); exprt &assertion=it->op0(); typecheck_expr(assertion); typecheck_expr(it->op1()); assertion.make_typecast(bool_typet()); make_constant(assertion); if(assertion.is_false()) { err_location(*it); throw "failed _Static_assert"; } else if(!assertion.is_true()) { // should warn/complain } it=components.erase(it); } else it++; } }
void c_typecheck_baset::typecheck_c_bit_field_type(c_bit_field_typet &type) { typecheck_type(type.subtype()); mp_integer i; { exprt &width_expr=static_cast<exprt &>(type.add(ID_size)); typecheck_expr(width_expr); make_constant_index(width_expr); if(to_integer(width_expr, i)) { error().source_location=type.source_location(); error() << "failed to convert bit field width" << eom; throw 0; } if(i<0) { error().source_location=type.source_location(); error() << "bit field width is negative" << eom; throw 0; } type.set_width(integer2size_t(i)); type.remove(ID_size); } const typet &subtype=follow(type.subtype()); std::size_t sub_width=0; if(subtype.id()==ID_bool) { // This is the 'proper' bool. sub_width=1; } else if(subtype.id()==ID_signedbv || subtype.id()==ID_unsignedbv || subtype.id()==ID_c_bool) { sub_width=to_bitvector_type(subtype).get_width(); } else if(subtype.id()==ID_c_enum_tag) { // These point to an enum, which has a sub-subtype, // which may be smaller or larger than int, and we thus have // to check. const typet &c_enum_type= follow_tag(to_c_enum_tag_type(subtype)); if(c_enum_type.id()==ID_incomplete_c_enum) { error().source_location=type.source_location(); error() << "bit field has incomplete enum type" << eom; throw 0; } sub_width=c_enum_type.subtype().get_int(ID_width); } else { error().source_location=type.source_location(); error() << "bit field with non-integer type: " << to_string(subtype) << eom; throw 0; } if(i>sub_width) { error().source_location=type.source_location(); error() << "bit field (" << i << " bits) larger than type (" << sub_width << " bits)" << eom; throw 0; } }
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; } }
void cpp_typecheckt::typecheck_enum_type(typet &type) { // first save qualifiers c_qualifierst qualifiers; qualifiers.read(type); cpp_enum_typet &enum_type=to_cpp_enum_type(type); bool anonymous=!enum_type.has_tag(); irep_idt base_name; if(anonymous) { // we fabricate a tag based on the enum constants contained base_name=enum_type.generate_anon_tag(); } else { const cpp_namet &tag=enum_type.tag(); if(tag.is_simple_name()) base_name=tag.get_base_name(); else { err_location(type); throw "enum tag is expected to be a simple name"; } } bool has_body=enum_type.has_body(); bool tag_only_declaration=enum_type.get_tag_only_declaration(); cpp_scopet &dest_scope= tag_scope(base_name, has_body, tag_only_declaration); const irep_idt symbol_name= dest_scope.prefix+"tag-"+id2string(base_name); // check if we have it symbol_tablet::symbolst::iterator previous_symbol= symbol_table.symbols.find(symbol_name); if(previous_symbol!=symbol_table.symbols.end()) { // we do! symbolt &symbol=previous_symbol->second; if(has_body) { err_location(type); str << "error: enum symbol `" << base_name << "' declared previously\n"; str << "location of previous definition: " << symbol.location; throw 0; } } else if(has_body) { std::string pretty_name= cpp_scopes.current_scope().prefix+id2string(base_name); // C++11 enumerations have an underlying type, // which defaults to int. // enums without underlying type may be 'packed'. if(type.subtype().is_nil()) type.subtype()=signed_int_type(); else { typecheck_type(type.subtype()); if(type.subtype().id()==ID_signedbv || type.subtype().id()==ID_unsignedbv) { } else { err_location(type); str << "underlying type must be integral"; throw 0; } } symbolt symbol; symbol.name=symbol_name; symbol.base_name=base_name; symbol.value.make_nil(); symbol.location=type.source_location(); symbol.mode=ID_cpp; symbol.module=module; symbol.type.swap(type); symbol.is_type=true; symbol.is_macro=false; symbol.pretty_name=pretty_name; // move early, must be visible before doing body symbolt *new_symbol; if(symbol_table.move(symbol, new_symbol)) throw "cpp_typecheckt::typecheck_enum_type: symbol_table.move() failed"; // put into scope cpp_idt &scope_identifier= cpp_scopes.put_into_scope(*new_symbol, dest_scope); scope_identifier.id_class=cpp_idt::CLASS; typecheck_enum_body(*new_symbol); } else { err_location(type); str << "use of enum `" << base_name << "' without previous declaration"; throw 0; } // create enum tag expression, and add the qualifiers type=c_enum_tag_typet(symbol_name); qualifiers.write(type); }
void c_typecheck_baset::typecheck_declaration( ansi_c_declarationt &declaration) { if(declaration.get_is_static_assert()) { assert(declaration.operands().size()==2); typecheck_expr(declaration.op0()); typecheck_expr(declaration.op1()); } else { // get storage spec c_storage_spect c_storage_spec(declaration.type()); // first typecheck the type of the declaration typecheck_type(declaration.type()); // mark as 'already typechecked' make_already_typechecked(declaration.type()); codet contract; { exprt spec_requires= static_cast<const exprt&>(declaration.find(ID_C_spec_requires)); contract.add(ID_C_spec_requires).swap(spec_requires); exprt spec_ensures= static_cast<const exprt&>(declaration.find(ID_C_spec_ensures)); contract.add(ID_C_spec_ensures).swap(spec_ensures); } // Now do declarators, if any. for(ansi_c_declarationt::declaratorst::iterator d_it=declaration.declarators().begin(); d_it!=declaration.declarators().end(); d_it++) { c_storage_spect full_spec(declaration.full_type(*d_it)); full_spec|=c_storage_spec; declaration.set_is_inline(full_spec.is_inline); declaration.set_is_static(full_spec.is_static); declaration.set_is_extern(full_spec.is_extern); declaration.set_is_thread_local(full_spec.is_thread_local); declaration.set_is_register(full_spec.is_register); declaration.set_is_typedef(full_spec.is_typedef); declaration.set_is_weak(full_spec.is_weak); symbolt symbol; declaration.to_symbol(*d_it, symbol); current_symbol=symbol; // now check other half of type typecheck_type(symbol.type); if(!full_spec.alias.empty()) { if(symbol.value.is_not_nil()) { error().source_location=symbol.location; error() << "alias attribute cannot be used with a body" << eom; throw 0; } // alias function need not have been declared yet, thus // can't lookup symbol.value=symbol_exprt(full_spec.alias); symbol.is_macro=true; } if(full_spec.section.empty()) apply_asm_label(full_spec.asm_label, symbol); else { std::string asm_name; asm_name=id2string(full_spec.section)+"$$"; if(!full_spec.asm_label.empty()) asm_name+=id2string(full_spec.asm_label); else asm_name+=id2string(symbol.name); apply_asm_label(asm_name, symbol); } irep_idt identifier=symbol.name; d_it->set_name(identifier); typecheck_symbol(symbol); // add code contract (if any); we typecheck this after the // function body done above, so as to have parameter symbols // available symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); assert(s_it!=symbol_table.symbols.end()); symbolt &new_symbol=s_it->second; typecheck_spec_expr(contract, ID_C_spec_requires); typet ret_type=empty_typet(); if(new_symbol.type.id()==ID_code) ret_type=to_code_type(new_symbol.type).return_type(); assert(parameter_map.empty()); if(ret_type.id()!=ID_empty) parameter_map["__CPROVER_return_value"]=ret_type; typecheck_spec_expr(contract, ID_C_spec_ensures); parameter_map.clear(); if(contract.find(ID_C_spec_requires).is_not_nil()) new_symbol.type.add(ID_C_spec_requires)= contract.find(ID_C_spec_requires); if(contract.find(ID_C_spec_ensures).is_not_nil()) new_symbol.type.add(ID_C_spec_ensures)= contract.find(ID_C_spec_ensures); } } }