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 cpp_typecheckt::typecheck_enum_body(symbolt &enum_symbol) { typet &type=enum_symbol.type; exprt &body=static_cast<exprt &>(type.add(ID_body)); irept::subt &components=body.get_sub(); typet enum_type(ID_symbol); enum_type.set(ID_identifier, enum_symbol.name); mp_integer i=0; Forall_irep(it, components) { const irep_idt &name=it->get(ID_name); if(it->find(ID_value).is_not_nil()) { exprt &value=static_cast<exprt &>(it->add(ID_value)); typecheck_expr(value); make_constant_index(value); if(to_integer(value, i)) throw "failed to produce integer for enum"; } exprt final_value(ID_constant, enum_type); final_value.set(ID_value, integer2string(i)); symbolt symbol; symbol.name=id2string(enum_symbol.name)+"::"+id2string(name); symbol.base_name=name; symbol.value.swap(final_value); symbol.location=static_cast<const locationt &>(it->find(ID_C_location)); symbol.mode=ID_cpp; symbol.module=module; symbol.type=enum_type; symbol.is_type=false; symbol.is_macro=true; symbolt *new_symbol; if(symbol_table.move(symbol, new_symbol)) throw "cpp_typecheckt::typecheck_enum_body: symbol_table.move() failed"; cpp_idt &scope_identifier= cpp_scopes.put_into_scope(*new_symbol); scope_identifier.id_class=cpp_idt::SYMBOL; ++i; } }
void cpp_typecheckt::check_fixed_size_array(typet &type) { if(type.id()==ID_array) { array_typet &array_type=to_array_type(type); if(array_type.size().is_not_nil()) make_constant_index(array_type.size()); // recursive call for multi-dimensional arrays check_fixed_size_array(array_type.subtype()); } }
designatort c_typecheck_baset::make_designator( const typet &src_type, const exprt &src) { assert(!src.operands().empty()); typet type=src_type; designatort designator; forall_operands(it, src) { const exprt &d_op=*it; designatort::entryt entry; entry.type=type; const typet &full_type=follow(entry.type); if(full_type.id()==ID_array) { if(d_op.id()!=ID_index) { err_location(d_op); error() << "expected array index designator" << eom; throw 0; } assert(d_op.operands().size()==1); exprt tmp_index=d_op.op0(); make_constant_index(tmp_index); mp_integer index, size; if(to_integer(tmp_index, index)) { err_location(d_op.op0()); error() << "expected constant array index designator" << eom; throw 0; } if(to_array_type(full_type).size().is_nil()) size=0; else if(to_integer(to_array_type(full_type).size(), size)) { err_location(d_op.op0()); error() << "expected constant array size" << eom; throw 0; } entry.index=integer2size_t(index); entry.size=integer2size_t(size); entry.subtype=full_type.subtype(); } else if(full_type.id()==ID_struct || full_type.id()==ID_union) { const struct_union_typet &struct_union_type= to_struct_union_type(full_type); if(d_op.id()!=ID_member) { err_location(d_op); error() << "expected member designator" << eom; throw 0; } const irep_idt &component_name=d_op.get(ID_component_name); if(struct_union_type.has_component(component_name)) { // a direct member entry.index=struct_union_type.component_number(component_name); entry.size=struct_union_type.components().size(); entry.subtype=struct_union_type.components()[entry.index].type(); } else { // We will search for anonymous members, // in a loop. This isn't supported by gcc, but icc does allow it. bool found=false, repeat; typet tmp_type=entry.type; do { repeat=false; unsigned number=0; const struct_union_typet::componentst &components= to_struct_union_type(follow(tmp_type)).components(); for(struct_union_typet::componentst::const_iterator c_it=components.begin(); c_it!=components.end(); c_it++, number++) { if(c_it->get_name()==component_name) { // done! entry.index=number; entry.size=components.size(); entry.subtype=components[entry.index].type(); entry.type=tmp_type; } else if(c_it->get_anonymous() && (follow(c_it->type()).id()==ID_struct || follow(c_it->type()).id()==ID_union) && has_component_rec( c_it->type(), component_name, *this)) { entry.index=number; entry.size=components.size(); entry.subtype=c_it->type(); entry.type=tmp_type; tmp_type=entry.subtype; designator.push_entry(entry); found=repeat=true; break; } } } while(repeat); if(!found) { err_location(d_op); error() << "failed to find struct component `" << component_name << "' in initialization of `" << to_string(struct_union_type) << "'" << eom; throw 0; } } } else { err_location(d_op); error() << "designated initializers cannot initialize `" << to_string(full_type) << "'" << eom; throw 0; } type=entry.subtype; designator.push_entry(entry); } assert(!designator.empty()); return designator; }
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_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_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; } }
codet cpp_typecheckt::cpp_constructor( const source_locationt &source_location, const exprt &object, const exprt::operandst &operands) { exprt object_tc=object; typecheck_expr(object_tc); elaborate_class_template(object_tc.type()); typet tmp_type(object_tc.type()); follow_symbol(tmp_type); assert(!is_reference(tmp_type)); if(tmp_type.id()==ID_array) { // We allow only one operand and it must be tagged with '#array_ini'. // Note that the operand is an array that is used for copy-initialization. // In the general case, a program is not allow to use this form of // construct. This way of initializing an array is used internaly only. // The purpose of the tag #arra_ini is to rule out ill-formed // programs. if(!operands.empty() && !operands.front().get_bool("#array_ini")) { error().source_location=source_location; error() << "bad array initializer" << eom; throw 0; } assert(operands.empty() || operands.size()==1); if(operands.empty() && cpp_is_pod(tmp_type)) { codet nil; nil.make_nil(); return nil; } const exprt &size_expr= to_array_type(tmp_type).size(); if(size_expr.id()=="infinity") { // don't initialize codet nil; nil.make_nil(); return nil; } exprt tmp_size=size_expr; make_constant_index(tmp_size); mp_integer s; if(to_integer(tmp_size, s)) { error().source_location=source_location; error() << "array size `" << to_string(size_expr) << "' is not a constant" << eom; throw 0; } /*if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt op_tc=operands.front(); typecheck_expr(op_tc); // Override constantness object_tc.type().set("#constant", false); object_tc.set("#lvalue", true); side_effect_exprt assign("assign"); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, op_tc); typecheck_side_effect_assignment(assign); new_code.expression()=assign; return new_code; } else*/ { codet new_code(ID_block); // for each element of the array, call the default constructor for(mp_integer i=0; i < s; ++i) { exprt::operandst tmp_operands; exprt constant=from_integer(i, index_type()); constant.add_source_location()=source_location; exprt index(ID_index); index.copy_to_operands(object); index.copy_to_operands(constant); index.add_source_location()=source_location; if(!operands.empty()) { exprt operand(ID_index); operand.copy_to_operands(operands.front()); operand.copy_to_operands(constant); operand.add_source_location()=source_location; tmp_operands.push_back(operand); } exprt i_code = cpp_constructor(source_location, index, tmp_operands); if(i_code.is_nil()) { new_code.is_nil(); break; } new_code.move_to_operands(i_code); } return new_code; } } else if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } if(operands_tc.empty()) { // a POD is NOT initialized new_code.make_nil(); } else if(operands_tc.size()==1) { // Override constantness object_tc.type().set(ID_C_constant, false); object_tc.set(ID_C_lvalue, true); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, operands_tc.front()); typecheck_side_effect_assignment(assign); new_code.expression()=assign; } else { error().source_location=source_location; error() << "initialization of POD requires one argument, " "but got " << operands.size() << eom; throw 0; } return new_code; } else if(tmp_type.id()==ID_union) { assert(0); // Todo: union } else if(tmp_type.id()==ID_struct) { exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } const struct_typet &struct_type= to_struct_type(tmp_type); // set most-derived bits codet block(ID_block); for(std::size_t i=0; i < struct_type.components().size(); i++) { const irept &component=struct_type.components()[i]; if(component.get(ID_base_name)!="@most_derived") continue; exprt member(ID_member, bool_typet()); member.set(ID_component_name, component.get(ID_name)); member.copy_to_operands(object_tc); member.add_source_location()=source_location; member.set(ID_C_lvalue, object_tc.get_bool(ID_C_lvalue)); exprt val=false_exprt(); if(!component.get_bool("from_base")) val=true_exprt(); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.move_to_operands(member, val); typecheck_side_effect_assignment(assign); code_expressiont code_exp; code_exp.expression()=assign; block.move_to_operands(code_exp); } // enter struct scope cpp_save_scopet save_scope(cpp_scopes); cpp_scopes.set_scope(struct_type.get(ID_name)); // find name of constructor const struct_typet::componentst &components= struct_type.components(); irep_idt constructor_name; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &type=it->type(); if(!it->get_bool(ID_from_base) && type.id()==ID_code && type.find(ID_return_type).id()==ID_constructor) { constructor_name=it->get(ID_base_name); break; } } // there is always a constructor for non-PODs assert(constructor_name!=""); irept cpp_name(ID_cpp_name); cpp_name.get_sub().push_back(irept(ID_name)); cpp_name.get_sub().back().set(ID_identifier, constructor_name); cpp_name.get_sub().back().set(ID_C_source_location, source_location); side_effect_expr_function_callt function_call; function_call.add_source_location()=source_location; function_call.function().swap(static_cast<exprt&>(cpp_name)); function_call.arguments().reserve(operands_tc.size()); for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) function_call.op1().copy_to_operands(*it); typecheck_side_effect_function_call(function_call); assert(function_call.get(ID_statement)==ID_temporary_object); exprt &initializer = static_cast<exprt &>(function_call.add(ID_initializer)); assert(initializer.id()==ID_code && initializer.get(ID_statement)==ID_expression); side_effect_expr_function_callt &func_ini= to_side_effect_expr_function_call(initializer.op0()); exprt &tmp_this=func_ini.arguments().front(); assert(tmp_this.id()==ID_address_of && tmp_this.op0().id()=="new_object"); exprt address_of(ID_address_of, typet(ID_pointer)); address_of.type().subtype()=object_tc.type(); address_of.copy_to_operands(object_tc); tmp_this.swap(address_of); if(block.operands().empty()) return to_code(initializer); else { block.move_to_operands(initializer); return block; } } else assert(false); codet nil; nil.make_nil(); return nil; }