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 boolbvt::convert_with_array( const array_typet &type, const exprt &op1, const exprt &op2, const bvt &prev_bv, bvt &next_bv) { if(is_unbounded_array(type)) { // can't do this error().source_location=type.source_location(); error() << "convert_with_array called for unbounded array" << eom; throw 0; } const exprt &array_size=type.size(); mp_integer size; if(to_integer(array_size, size)) { error().source_location=type.source_location(); error() << "convert_with_array expects constant array size" << eom; throw 0; } const bvt &op2_bv=convert_bv(op2); if(size*op2_bv.size()!=prev_bv.size()) { error().source_location=type.source_location(); error() << "convert_with_array: unexpected operand 2 width" << eom; throw 0; } // Is the index a constant? mp_integer op1_value; if(!to_integer(op1, op1_value)) { // Yes, it is! next_bv=prev_bv; if(op1_value>=0 && op1_value<size) // bounds check { std::size_t offset=integer2unsigned(op1_value*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]=op2_bv[j]; } return; } typet counter_type=op1.type(); for(mp_integer i=0; i<size; i=i+1) { exprt counter=from_integer(i, counter_type); literalt eq_lit=convert(equal_exprt(op1, counter)); std::size_t offset=integer2unsigned(i*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]= prop.lselect(eq_lit, op2_bv[j], prev_bv[offset+j]); } }