bool goto_program_dereferencet::has_failed_symbol( const exprt &expr, const symbolt *&symbol) { if(expr.id()==ID_symbol) { if(expr.get_bool("#invalid_object")) return false; const symbolt &ptr_symbol=ns.lookup(expr); const irep_idt &failed_symbol= ptr_symbol.type.get("#failed_symbol"); if(failed_symbol==irep_idt()) return false; return !ns.lookup(failed_symbol, symbol); } return false; }
void gen_binary(exprt &expr, const std::string &id, bool default_value) { if(expr.operands().size()==0) { if(default_value) expr.make_true(); else expr.make_false(); } else if(expr.operands().size()==1) { exprt tmp; tmp.swap(expr.op0()); expr.swap(tmp); } else { expr.id(id); expr.type()=typet("bool"); } }
void cnf_join_binary(exprt &expr) { Forall_operands(it, expr) cnf_join_binary(*it); if(expr.id()==ID_and || expr.id()==ID_or || expr.id()==ID_xor || expr.id()==ID_bitand || expr.id()==ID_bitor || expr.id()==ID_bitxor) { exprt tmp; if(expr.operands().size()==1) { tmp.swap(expr.op0()); expr.swap(tmp); } else { unsigned count=0; forall_operands(it, expr) { if(it->id()==expr.id()) count+=it->operands().size(); else count++; } tmp.operands().reserve(count); Forall_operands(it, expr) { if(it->id()==expr.id()) { Forall_operands(it2, *it) tmp.move_to_operands(*it2); } else tmp.move_to_operands(*it); } expr.operands().swap(tmp.operands()); } }
void predicatest::make_expr_passive_rec( exprt& phi, const namespacet& ns, const unsigned subscript) { Forall_operands(it, phi) make_expr_passive_rec(*it, ns, subscript); if(phi.id()==ID_symbol) { symbol_exprt &phi_sym=to_symbol_expr(phi); const irep_idt &identifier=phi_sym.get_identifier(); assert(identifier.as_string().find('#')==std::string::npos); if(is_procedure_local(ns.lookup(identifier))) { std::ostringstream os; os << identifier << '#' << subscript; phi_sym.set_identifier(os.str()); } } }
void trans_wpt::wp_rec(exprt &expr) { Forall_operands(it, expr) wp_rec(*it); if(expr.id()==ID_symbol) { const irep_idt &identifier=expr.get(ID_identifier); const symbolt &symbol=ns.lookup(identifier); if(symbol.is_macro) { // it's just a macro expr=symbol.value; wp_rec(expr); } else if(symbol.is_statevar) { next_state_functionst::const_iterator it=next_state_functions.find(identifier); if(it==next_state_functions.end()) { throw "trans_wpt: no next state function for "+ id2string(identifier); } else { // replace! expr=it->second; } } else { // it's an input or so throw "trans_wpt: unexpected symbol: "+id2string(identifier); } } }
literalt cvc_convt::convert(const exprt &expr) { //out << "%% E: " << expr << std::endl; if(expr.type().id()!=ID_bool) { std::string msg="cvc_convt::convert got " "non-boolean expression: "; msg+=expr.pretty(); throw msg; } // Three special cases in which we don't need to generate // a handle. if(expr.is_true()) return const_literal(true); else if(expr.is_false()) return const_literal(false); else if(expr.id()==ID_literal) return to_literal_expr(expr).get_literal(); // Generate new handle literalt l(no_boolean_variables, false); no_boolean_variables++; find_symbols(expr); // define new handle out << "ASSERT "; convert_literal(l); out << " <=> ("; convert_expr(expr); out << ");" << std::endl << std::endl; return l; }
bool replace_symbolt::replace(exprt &dest) { if(dest.id()=="symbol") { expr_mapt::const_iterator it= expr_map.find(dest.identifier()); if(it!=expr_map.end()) { dest=it->second; return false; } } bool result=true; Forall_operands(it, dest) result=replace(*it) && result; result=replace(dest.type()) && result; return result; }
void local_SSAt::replace_side_effects_rec( exprt &expr, locationt loc, unsigned &counter) const { Forall_operands(it, expr) replace_side_effects_rec(*it, loc, counter); if(expr.id()==ID_side_effect) { const side_effect_exprt &side_effect_expr= to_side_effect_expr(expr); const irep_idt statement=side_effect_expr.get_statement(); if(statement==ID_nondet) { // turn into nondet_symbol exprt nondet_symbol(ID_nondet_symbol, expr.type()); counter++; const irep_idt identifier= "ssa::nondet"+ i2string(loc->location_number)+ "."+i2string(counter)+suffix; nondet_symbol.set(ID_identifier, identifier); expr.swap(nondet_symbol); } else if(statement==ID_malloc) { counter++; std::string tmp_suffix= i2string(loc->location_number)+ "."+i2string(counter)+suffix; expr=malloc_ssa(side_effect_expr, tmp_suffix, ns); } else throw "unexpected side effect: "+id2string(statement); } }
void rw_sett::read_write_rec( const exprt &expr, bool r, bool w, const std::string &suffix, const guardt &guard) { if(expr.id()==ID_symbol) { const symbol_exprt &symbol_expr=to_symbol_expr(expr); const symbolt *symbol; if(!ns.lookup(symbol_expr.get_identifier(), symbol)) { if(!symbol->static_lifetime) return; // ignore for now if(symbol->thread_local) return; // must ignore if(symbol->name=="c::__CPROVER_alloc" || symbol->name=="c::__CPROVER_alloc_size" || symbol->name=="c::stdin" || symbol->name=="c::stdout" || symbol->name=="c::stderr" || symbol->name=="c::sys_nerr") return; // ignore for now } irep_idt object=id2string(symbol_expr.get_identifier())+suffix; entryt &entry=entries[object]; entry.object=object; entry.r=entry.r || r; entry.w=entry.w || w; entry.guard=guard.as_expr(); } else if(expr.id()=="member")
void goto_checkt::overflow_check(const exprt &expr, const guardt &guard) { if (!options.get_bool_option("overflow-check")) return; // first, check type if (expr.type().id() != "signedbv") return; // add overflow subgoal exprt overflow("overflow-" + expr.id_string(), bool_typet()); overflow.operands() = expr.operands(); if (expr.id() == "typecast") { if (expr.operands().size() != 1) throw "typecast takes one operand"; const typet &old_type = expr.op0().type(); unsigned new_width = atoi(expr.type().width().c_str()); unsigned old_width = atoi(old_type.width().c_str()); if (old_type.id() == "unsignedbv") new_width--; if (new_width >= old_width) return; overflow.id(overflow.id_string() + "-" + i2string(new_width)); } overflow.make_not(); add_guarded_claim(overflow, "arithmetic overflow on " + expr.id_string(), "overflow", expr.find_location(), guard); }
exprt remove_const_function_pointerst::replace_const_symbols( const exprt &expression) const { if(expression.id()==ID_symbol) { if(is_const_expression(expression)) { const symbolt &symbol= symbol_table.lookup(expression.get(ID_identifier)); if(symbol.type.id()!=ID_code) { const exprt &symbol_value=symbol.value; return replace_const_symbols(symbol_value); } else { return expression; } } else { return expression; } } else { exprt const_symbol_cleared_expr=expression; const_symbol_cleared_expr.operands().clear(); for(const exprt &op : expression.operands()) { exprt const_symbol_cleared_op=replace_const_symbols(op); const_symbol_cleared_expr.operands().push_back(const_symbol_cleared_op); } return const_symbol_cleared_expr; } }
void goto_symext::replace_array_equal(exprt &expr) { if(expr.id()==ID_array_equal) { assert(expr.operands().size()==2); // we expect two index expressions process_array_expr(expr.op0()); process_array_expr(expr.op1()); // type checking if(ns.follow(expr.op0().type())!= ns.follow(expr.op1().type())) expr=false_exprt(); else { equal_exprt equality_expr(expr.op0(), expr.op1()); expr.swap(equality_expr); } } Forall_operands(it, expr) replace_array_equal(*it); }
exprt ranking_synthesis_qbf_bitwiset::coefficient(const exprt &expr) { assert(expr.id()==ID_symbol); exprt &entry = coefficient_map[expr]; if(entry==exprt()) { irep_idt ident=expr.get_string(ID_identifier) + "$C"; // set up a new coefficient entry.id(ID_symbol); entry.set(ID_identifier, ident); // adjust the coefficient type entry.type()=expr.type(); assert(expr.type().id()==ID_signedbv || expr.type().id()==ID_unsignedbv || expr.type().id()==ID_bool); } return entry; }
void rd_range_domaint::assign( const namespacet &ns, locationt from, const exprt &lhs, const mp_integer &size) { if(lhs.id()==ID_typecast) assign(ns, from, to_typecast_expr(lhs).op(), size); else if(lhs.id()==ID_if) assign_if(ns, from, to_if_expr(lhs), size); else if(lhs.id()==ID_dereference) assign_dereference(ns, from, to_dereference_expr(lhs), size); else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) assign_byte_extract(ns, from, to_byte_extract_expr(lhs), size); else if(lhs.id()==ID_symbol || lhs.id()==ID_index || lhs.id()==ID_member) assign(ns, from, lhs, compute_pointer_offset(ns, lhs), size); else throw "assignment to `"+lhs.id_string()+"' not handled"; }
bool simplify_exprt::simplify_floatbv_op(exprt &expr) { const typet &type=ns.follow(expr.type()); if(type.id()!=ID_floatbv) return true; assert(expr.operands().size()==3); exprt op0=expr.op0(); exprt op1=expr.op1(); exprt op2=expr.op2(); // rounding mode assert(ns.follow(op0.type())==type); assert(ns.follow(op1.type())==type); // Remember that floating-point addition is _NOT_ associative. // Thus, we don't re-sort the operands. // We only merge constants! if(op0.is_constant() && op1.is_constant() && op2.is_constant()) { ieee_floatt v0(to_constant_expr(op0)); ieee_floatt v1(to_constant_expr(op1)); mp_integer rounding_mode; if(!to_integer(op2, rounding_mode)) { v0.rounding_mode=(ieee_floatt::rounding_modet)integer2size_t(rounding_mode); v1.rounding_mode=v0.rounding_mode; ieee_floatt result=v0; if(expr.id()==ID_floatbv_plus) result+=v1; else if(expr.id()==ID_floatbv_minus) result-=v1; else if(expr.id()==ID_floatbv_mult) result*=v1; else if(expr.id()==ID_floatbv_div) result/=v1; else assert(false); expr=result.to_expr(); return false; } } // division by one? Exact for all rounding modes. if (expr.id()==ID_floatbv_div && op1.is_constant() && op1.is_one()) { exprt tmp; tmp.swap(op0); expr.swap(tmp); return false; } return true; }
exprt flatten_byte_extract( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian); assert(src.operands().size()==2); bool little_endian; if(src.id()==ID_byte_extract_little_endian) little_endian=true; else if(src.id()==ID_byte_extract_big_endian) little_endian=false; else assert(false); if(src.id()==ID_byte_extract_big_endian) throw "byte_extract flattening of big endian not done yet"; unsigned width= integer2long(pointer_offset_size(ns, src.type())); const typet &t=src.op0().type(); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // byte-array? if((subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv) && subtype.get_int(ID_width)==8) { // get 'width'-many bytes, and concatenate exprt::operandst op; op.resize(width); for(unsigned i=0; i<width; i++) { // the most significant byte comes first in the concatenation! unsigned offset_i= little_endian?(width-i-1):i; plus_exprt offset(from_integer(offset_i, src.op1().type()), src.op1()); index_exprt index_expr(subtype); index_expr.array()=src.op0(); index_expr.index()=offset; op[i]=index_expr; } if(width==1) return op[0]; else // width>=2 { concatenation_exprt concatenation(src.type()); concatenation.operands().swap(op); return concatenation; } } else // non-byte array { const exprt &root=src.op0(); const exprt &offset=src.op1(); const typet &array_type=ns.follow(root.type()); const typet &offset_type=ns.follow(offset.type()); const typet &element_type=ns.follow(array_type.subtype()); mp_integer element_width=pointer_offset_size(ns, element_type); if(element_width==-1) // failed throw "failed to flatten non-byte array with unknown element width"; mp_integer result_width=pointer_offset_size(ns, src.type()); mp_integer num_elements=(element_width+result_width-2)/element_width+1; // compute new root and offset concatenation_exprt concat( unsignedbv_typet(integer2long(element_width*8*num_elements))); exprt first_index= (element_width==1)?offset : div_exprt(offset, from_integer(element_width, offset_type)); // 8*offset/el_w for(mp_integer i=num_elements; i>0; --i) { plus_exprt index(first_index, from_integer(i-1, offset_type)); concat.copy_to_operands(index_exprt(root, index)); } // the new offset is width%offset exprt new_offset= (element_width==1)?from_integer(0, offset_type): mod_exprt(offset, from_integer(element_width, offset_type)); // build new byte-extract expression exprt tmp(src.id(), src.type()); tmp.copy_to_operands(concat, new_offset); return tmp; } } else // non-array { // We turn that into logical right shift and extractbits const exprt &offset=src.op1(); const typet &offset_type=ns.follow(offset.type()); mult_exprt times_eight(offset, from_integer(8, offset_type)); lshr_exprt left_shift(src.op0(), times_eight); extractbits_exprt extractbits; extractbits.src()=left_shift; extractbits.type()=src.type(); extractbits.upper()=from_integer(width*8-1, offset_type); extractbits.lower()=from_integer(0, offset_type); return extractbits; } }
exprt flatten_byte_update( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_update_little_endian || src.id()==ID_byte_update_big_endian); assert(src.operands().size()==3); mp_integer element_size= pointer_offset_size(ns, src.op2().type()); const typet &t=ns.follow(src.op0().type()); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // array of bitvectors? if(subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv || subtype.id()==ID_floatbv) { mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) throw "can't flatten byte_update for sub-type without size"; // byte array? if(sub_size==1) { // apply 'array-update-with' element_size times exprt result=src.op0(); for(mp_integer i=0; i<element_size; ++i) { exprt i_expr=from_integer(i, ns.follow(src.op1().type())); exprt new_value; if(i==0 && element_size==1) // bytes? { new_value=src.op2(); if(new_value.type()!=subtype) new_value.make_typecast(subtype); } else { exprt byte_extract_expr( src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian: src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian: throw "unexpected src.id()", subtype); byte_extract_expr.copy_to_operands(src.op2(), i_expr); new_value=flatten_byte_extract(byte_extract_expr, ns); } exprt where=plus_exprt(src.op1(), i_expr); with_exprt with_expr; with_expr.type()=src.type(); with_expr.old()=result; with_expr.where()=where; with_expr.new_value()=new_value; result.swap(with_expr); } return result; } else // sub_size!=1 { if(element_size==1) // byte-granularity update { div_exprt div_offset(src.op1(), from_integer(sub_size, src.op1().type())); mod_exprt mod_offset(src.op1(), from_integer(sub_size, src.op1().type())); index_exprt index_expr(src.op0(), div_offset, array_type.subtype()); exprt byte_update_expr(src.id(), array_type.subtype()); byte_update_expr.copy_to_operands(index_expr, mod_offset, src.op2()); // Call recurisvely, the array is gone! exprt flattened_byte_update_expr= flatten_byte_update(byte_update_expr, ns); with_exprt with_expr( src.op0(), div_offset, flattened_byte_update_expr); return with_expr; } else throw "flatten_byte_update can only do byte updates of non-byte arrays right now"; } } else { throw "flatten_byte_update can only do arrays of scalars right now"; } } else if(t.id()==ID_signedbv || t.id()==ID_unsignedbv || t.id()==ID_floatbv) { // do a shift, mask and OR unsigned width=to_bitvector_type(t).get_width(); if(element_size*8>width) throw "flatten_byte_update to update element that is too large"; // build mask exprt mask= bitnot_exprt( from_integer(power(2, element_size*8)-1, unsignedbv_typet(width))); const typet &offset_type=ns.follow(src.op1().type()); mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type)); // shift the mask shl_exprt shl_expr(mask, offset_times_eight); // do the 'AND' bitand_exprt bitand_expr(src.op0(), mask); // zero-extend the value concatenation_exprt value_extended( from_integer(0, unsignedbv_typet(width-integer2long(element_size)*8)), src.op2(), t); // shift the value shl_exprt value_shifted(value_extended, offset_times_eight); // do the 'OR' bitor_exprt bitor_expr(bitand_expr, value_shifted); return bitor_expr; } else { throw "flatten_byte_update can only do array and scalars right now"; } }
literalt boolbvt::convert_overflow(const exprt &expr) { const exprt::operandst &operands=expr.operands(); if(expr.id()==ID_overflow_plus || expr.id()==ID_overflow_minus) { if(operands.size()!=2) throw "operator "+expr.id_string()+" takes two operands"; const bvt &bv0=convert_bv(operands[0]); const bvt &bv1=convert_bv(operands[1]); if(bv0.size()!=bv1.size()) return SUB::convert_rest(expr); bv_utilst::representationt rep= expr.op0().type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; return expr.id()==ID_overflow_minus? bv_utils.overflow_sub(bv0, bv1, rep): bv_utils.overflow_add(bv0, bv1, rep); } else if(expr.id()==ID_overflow_mult) { if(operands.size()!=2) throw "operator "+expr.id_string()+" takes two operands"; if(operands[0].type().id()!=ID_unsignedbv && operands[0].type().id()!=ID_signedbv) return SUB::convert_rest(expr); bvt bv0=convert_bv(operands[0]); bvt bv1=convert_bv(operands[1]); if(bv0.size()!=bv1.size()) throw "operand size mismatch on overflow-*"; bv_utilst::representationt rep= operands[0].type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; if(operands[0].type()!=operands[1].type()) throw "operand type mismatch on overflow-*"; assert(bv0.size()==bv1.size()); unsigned old_size=bv0.size(); unsigned new_size=old_size*2; // sign/zero extension bv0=bv_utils.extension(bv0, new_size, rep); bv1=bv_utils.extension(bv1, new_size, rep); bvt result=bv_utils.multiplier(bv0, bv1, rep); if(rep==bv_utilst::UNSIGNED) { bvt bv_overflow; bv_overflow.reserve(old_size); // get top result bits for(unsigned i=old_size; i<result.size(); i++) bv_overflow.push_back(result[i]); return prop.lor(bv_overflow); } else { bvt bv_overflow; bv_overflow.reserve(old_size); // get top result bits, plus one more assert(old_size!=0); for(unsigned i=old_size-1; i<result.size(); i++) bv_overflow.push_back(result[i]); // these need to be either all 1's or all 0's literalt all_one=prop.land(bv_overflow); literalt all_zero=prop.lnot(prop.lor(bv_overflow)); return prop.lnot(prop.lor(all_one, all_zero)); } } else if(expr.id()==ID_overflow_unary_minus) { if(operands.size()!=1) throw "operator "+expr.id_string()+" takes one operand"; const bvt &bv=convert_bv(operands[0]); return bv_utils.overflow_negate(bv); } else if(has_prefix(expr.id_string(), "overflow-typecast-")) { unsigned bits=atoi(expr.id().c_str()+18); const exprt::operandst &operands=expr.operands(); if(operands.size()!=1) throw "operator "+expr.id_string()+" takes one operand"; const exprt &op=operands[0]; const bvt &bv=convert_bv(op); if(bits>=bv.size() || bits==0) throw "overflow-typecast got wrong number of bits"; // signed or unsigned? if(op.type().id()==ID_signedbv) { bvt tmp_bv; for(unsigned i=bits; i<bv.size(); i++) tmp_bv.push_back(prop.lxor(bv[bits-1], bv[i])); return prop.lor(tmp_bv); } else { bvt tmp_bv; for(unsigned i=bits; i<bv.size(); i++) tmp_bv.push_back(bv[i]); return prop.lor(tmp_bv); } } return SUB::convert_rest(expr); }
void cvc_convt::convert_expr(const exprt &expr) { const exprt::operandst &op=expr.operands(); if(expr.id()==ID_implies) { if(op.size()!=2) throw "implication takes two operands"; out << "("; convert_expr(op[0]); out << ") => ("; convert_expr(op[1]); out << ")"; } else if(expr.id()==ID_constraint_select_one) { if(op.size()<2) throw "constraint_select_one takes at least two operands"; // TODO throw "cvc_convt::convert_expr needs constraint_select_one"; } else if(expr.id()==ID_or || expr.id()==ID_and || expr.id()==ID_xor || expr.id()==ID_nor || expr.id()==ID_nand) { if(op.empty()) throw "operator `"+expr.id_string()+"' takes at least one operand"; else if(op.size()==1) convert_expr(op[0]); else { forall_expr(it, op) { if(it!=op.begin()) { if(expr.id()==ID_or) out << " OR "; else if(expr.id()==ID_nor) out << " NOR "; else if(expr.id()==ID_and) out << " AND "; else if(expr.id()==ID_nand) out << " NAND "; else if(expr.id()==ID_xor) out << " XOR "; else assert(false); } out << "("; convert_expr(*it); out << ")"; } } } else if(expr.id()==ID_not)
void jsil_typecheckt::typecheck_expr_main(exprt &expr) { if(expr.id()==ID_code) { err_location(expr); error() << "typecheck_expr_main got code: " << expr.pretty() << eom; throw 0; } else if(expr.id()==ID_symbol) typecheck_symbol_expr(to_symbol_expr (expr)); else if(expr.id()==ID_constant) { } else { // expressions are expected not to have type set just yet assert(expr.type().is_nil()||expr.type().id().empty()); if (expr.id()==ID_null || expr.id()=="undefined" || expr.id()==ID_empty) typecheck_expr_constant(expr); else if(expr.id()=="null_type" || expr.id()=="undefined_type" || expr.id()==ID_boolean || expr.id()==ID_string || expr.id()=="number" || expr.id()=="builtin_object" || expr.id()=="user_object" || expr.id()=="object" || expr.id()==ID_reference || expr.id()==ID_member || expr.id()=="variable") expr.type()=jsil_kind(); else if(expr.id()=="proto" || expr.id()=="fid" || expr.id()=="scope" || expr.id()=="constructid" || expr.id()=="primvalue" || expr.id()=="targetfunction" || expr.id()==ID_class) { // TODO: have a special type for builtin fields expr.type()=string_typet(); } else if(expr.id()==ID_not) typecheck_expr_unary_boolean(expr); else if(expr.id()=="string_to_num") typecheck_expr_unary_string(expr); else if(expr.id()==ID_unary_minus || expr.id()=="num_to_int32" || expr.id()=="num_to_uint32" || expr.id()==ID_bitnot) { typecheck_expr_unary_num(expr); expr.type()=floatbv_typet(); } else if(expr.id()=="num_to_string") { typecheck_expr_unary_num(expr); expr.type()=string_typet(); } else if(expr.id()==ID_equal) typecheck_exp_binary_equal(expr); else if(expr.id()==ID_lt || expr.id()==ID_le) typecheck_expr_binary_compare(expr); else if(expr.id()==ID_plus || expr.id()==ID_minus || expr.id()==ID_mult || expr.id()==ID_div || expr.id()==ID_mod || expr.id()==ID_bitand || expr.id()==ID_bitor || expr.id()==ID_bitxor || expr.id()==ID_shl || expr.id()==ID_shr || expr.id()==ID_lshr) typecheck_expr_binary_arith(expr); else if(expr.id()==ID_and || expr.id()==ID_or) typecheck_expr_binary_boolean(expr); else if(expr.id()=="subtype_of") typecheck_expr_subtype(expr); else if(expr.id()==ID_concatenation) typecheck_expr_concatenation(expr); else if(expr.id()=="ref") typecheck_expr_ref(expr); else if(expr.id()=="field") typecheck_expr_field(expr); else if(expr.id()==ID_base) typecheck_expr_base(expr); else if(expr.id()==ID_typeof) expr.type()=jsil_kind(); else if(expr.id()=="new") expr.type()=jsil_user_object_type(); else if(expr.id()=="hasField") typecheck_expr_has_field(expr); else if(expr.id()==ID_index) typecheck_expr_index(expr); else if(expr.id()=="delete") typecheck_expr_delete(expr); else if(expr.id()=="protoField") typecheck_expr_proto_field(expr); else if(expr.id()=="protoObj") typecheck_expr_proto_obj(expr); else if(expr.id()==ID_side_effect) typecheck_expr_side_effect_throw(to_side_effect_expr_throw(expr)); else { err_location(expr); error() << "unexpected expression: " << expr.pretty() << eom; throw 0; } } }
void cvc_convt::convert_address_of_rec(const exprt &expr) { if(expr.id()==ID_symbol || expr.id()==ID_constant || expr.id()==ID_string_constant) { out << "(# object:=" << pointer_logic.add_object(expr) << ", offset:=" << bin_zero(config.ansi_c.pointer_width) << " #)"; } else if(expr.id()==ID_index) { if(expr.operands().size()!=2) throw "index takes two operands"; const exprt &array=expr.op0(); const exprt &index=expr.op1(); if(index.is_zero()) { if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); } else { out << "(LET P: "; out << cvc_pointer_type(); out << " = "; if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } } else if(expr.id()==ID_member) { if(expr.operands().size()!=1) throw "member takes one operand"; const exprt &struct_op=expr.op0(); out << "(LET P: "; out << cvc_pointer_type(); out << " = "; convert_address_of_rec(struct_op); const irep_idt &component_name= to_member_expr(expr).get_component_name(); mp_integer offset=member_offset( to_struct_type(struct_op.type()), component_name, ns); typet index_type(ID_unsignedbv); index_type.set(ID_width, config.ansi_c.pointer_width); exprt index=from_integer(offset, index_type); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } else throw "don't know how to take address of: "+expr.id_string(); }
void boolbvt::convert_mult(const exprt &expr, bvt &bv) { unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); bv.resize(width); const exprt::operandst &operands=expr.operands(); if(operands.size()==0) throw "mult without operands"; const exprt &op0=expr.op0(); bool no_overflow=expr.id()=="no-overflow-mult"; if(expr.type().id()==ID_fixedbv) { if(op0.type()!=expr.type()) throw "multiplication with mixed types"; bv=convert_bv(op0); if(bv.size()!=width) throw "convert_mult: unexpected operand width"; unsigned fraction_bits= to_fixedbv_type(expr.type()).get_fraction_bits(); // do a sign extension by fraction_bits bits bv=bv_utils.sign_extension(bv, bv.size()+fraction_bits); for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=expr.type()) throw "multiplication with mixed types"; bvt op=convert_bv(*it); if(op.size()!=width) throw "convert_mult: unexpected operand width"; op=bv_utils.sign_extension(op, bv.size()); bv=bv_utils.signed_multiplier(bv, op); } // cut it down again bv.erase(bv.begin(), bv.begin()+fraction_bits); return; } else if(expr.type().id()==ID_floatbv) { if(op0.type()!=expr.type()) throw "multiplication with mixed types"; bv=convert_bv(op0); if(bv.size()!=width) throw "convert_mult: unexpected operand width"; float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(expr.type()); for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=expr.type()) throw "multiplication with mixed types"; const bvt &op=convert_bv(*it); if(op.size()!=width) throw "convert_mult: unexpected operand width"; bv=float_utils.mul(bv, op); } return; } else if(expr.type().id()==ID_unsignedbv || expr.type().id()==ID_signedbv) { if(op0.type()!=expr.type()) throw "multiplication with mixed types"; bv_utilst::representationt rep= expr.type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; bv=convert_bv(op0); if(bv.size()!=width) throw "convert_mult: unexpected operand width"; for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=expr.type()) throw "multiplication with mixed types"; const bvt &op=convert_bv(*it); if(op.size()!=width) throw "convert_mult: unexpected operand width"; if(no_overflow) bv=bv_utils.multiplier_no_overflow(bv, op, rep); else bv=bv_utils.multiplier(bv, op, rep); } return; } conversion_failed(expr, bv); }
exprt c_typecheck_baset::do_initializer_list( const exprt &value, const typet &type, bool force_constant) { assert(value.id()==ID_initializer_list); const typet &full_type=follow(type); exprt result; if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } else if(full_type.id()==ID_array) { if(to_array_type(full_type).size().is_nil()) { // start with empty array result=exprt(ID_array, full_type); result.add_source_location()=value.source_location(); } else { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } // 6.7.9, 14: An array of character type may be initialized by a character // string literal or UTF-8 string literal, optionally enclosed in braces. if(value.operands().size()>=1 && value.op0().id()==ID_string_constant && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { if(value.operands().size()>1) { warning().source_location=value.find_source_location(); warning() << "ignoring excess initializers" << eom; } return do_initializer_rec(value.op0(), type, force_constant); } } else { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.operands().size()==1) return do_initializer_rec(value.op0(), type, force_constant); err_location(value); error() << "cannot initialize `" << to_string(full_type) << "' with an initializer list" << eom; throw 0; } designatort current_designator; designator_enter(type, current_designator); forall_operands(it, value) { do_designated_initializer( result, current_designator, *it, force_constant); // increase designator -- might go up increment_designator(current_designator); }
void value_sett::get_value_set_rec( const exprt &expr, object_mapt &dest, const std::string &suffix, const typet &original_type, const namespacet &ns) const { #if 0 std::cout << "GET_VALUE_SET_REC EXPR: " << from_expr(ns, "", expr) << "\n"; std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << std::endl; #endif const typet &expr_type=ns.follow(expr.type()); if(expr.id()==ID_unknown || expr.id()==ID_invalid) { insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_index) { assert(expr.operands().size()==2); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_array || type.id()==ID_incomplete_array); get_value_set_rec(expr.op0(), dest, "[]"+suffix, original_type, ns); } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_struct || type.id()==ID_union || type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union); const std::string &component_name= expr.get_string(ID_component_name); get_value_set_rec(expr.op0(), dest, "."+component_name+suffix, original_type, ns); } else if(expr.id()==ID_symbol) { irep_idt identifier=to_symbol_expr(expr).get_identifier(); // is it a pointer, integer, array or struct? if(expr_type.id()==ID_pointer || expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv || expr_type.id()==ID_struct || expr_type.id()==ID_union || expr_type.id()==ID_array) { // look it up valuest::const_iterator v_it= values.find(id2string(identifier)+suffix); // try first component name as suffix if not yet found if(v_it==values.end() && (expr_type.id()==ID_struct || expr_type.id()==ID_union)) { const struct_union_typet &struct_union_type= to_struct_union_type(expr_type); const std::string first_component_name= struct_union_type.components().front().get_string(ID_name); v_it=values.find( id2string(identifier)+"."+first_component_name+suffix); } // not found? try without suffix if(v_it==values.end()) v_it=values.find(identifier); if(v_it!=values.end()) make_union(dest, v_it->second.object_map); else insert(dest, exprt(ID_unknown, original_type)); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three operands"; get_value_set_rec(expr.op1(), dest, suffix, original_type, ns); get_value_set_rec(expr.op2(), dest, suffix, original_type, ns); } else if(expr.id()==ID_address_of) { if(expr.operands().size()!=1) throw expr.id_string()+" expected to have one operand"; get_reference_set(expr.op0(), dest, ns); } else if(expr.id()==ID_dereference) { object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it1=object_map.begin(); it1!=object_map.end(); it1++) { const exprt &object=object_numbering[it1->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.id()=="reference_to") { // old stuff, will go away object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it=object_map.begin(); it!=object_map.end(); it++) { const exprt &object=object_numbering[it->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.is_constant()) { // check if NULL if(expr.get(ID_value)==ID_NULL && expr_type.id()==ID_pointer) { insert(dest, exprt("NULL-object", expr_type.subtype()), 0); } else if(expr_type.id()==ID_unsignedbv || expr_type.id()==ID_signedbv) { // an integer constant got turned into a pointer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_typecast) { if(expr.operands().size()!=1) throw "typecast takes one operand"; // let's see what gets converted to what const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_pointer) { // pointer-to-pointer -- we just ignore these get_value_set_rec(expr.op0(), dest, suffix, original_type, ns); } else if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv) { // integer-to-pointer if(expr.op0().is_zero()) insert(dest, exprt("NULL-object", expr_type.subtype()), 0); else { // see if we have something for the integer object_mapt tmp; get_value_set_rec(expr.op0(), tmp, suffix, original_type, ns); if(tmp.read().size()==0) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else if(tmp.read().size()==1 && object_numbering[tmp.read().begin()->first].id()==ID_unknown) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else { // use as is dest.write().insert(tmp.read().begin(), tmp.read().end()); } } } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_plus || expr.id()==ID_minus) { if(expr.operands().size()<2) throw expr.id_string()+" expected to have at least two operands"; object_mapt pointer_expr_set; mp_integer i; bool i_is_set=false; // special case for pointer+integer if(expr.operands().size()==2 && expr_type.id()==ID_pointer) { exprt ptr_operand; if(expr.op0().type().id()!=ID_pointer && expr.op0().is_constant()) { i_is_set=!to_integer(expr.op0(), i); ptr_operand=expr.op1(); } else { i_is_set=!to_integer(expr.op1(), i); ptr_operand=expr.op0(); } if(i_is_set) { i*=pointer_offset_size(ptr_operand.type().subtype(), ns); if(expr.id()==ID_minus) i.negate(); } get_value_set_rec( ptr_operand, pointer_expr_set, "", ptr_operand.type(), ns); } else { // we get the points-to for all operands, even integers forall_operands(it, expr) { get_value_set_rec( *it, pointer_expr_set, "", it->type(), ns); } } for(object_map_dt::const_iterator it=pointer_expr_set.read().begin(); it!=pointer_expr_set.read().end(); it++) { objectt object=it->second; // adjust by offset if(object.offset_is_zero() && i_is_set) object.offset=i; else object.offset_is_set=false; insert(dest, it->first, object); } }
std::string as_vcd_binary( const exprt &expr, const namespacet &ns) { const typet &type=ns.follow(expr.type()); if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_bv || type.id()==ID_fixedbv || type.id()==ID_floatbv || type.id()==ID_pointer) return expr.get_string(ID_value); } else if(expr.id()==ID_array) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_struct) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_union) { assert(expr.operands().size()==1); return as_vcd_binary(expr.op0(), ns); } // build "xxx" mp_integer width; if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_floatbv || type.id()==ID_fixedbv || type.id()==ID_pointer || type.id()==ID_bv) width=string2integer(type.get_string(ID_width)); else width=pointer_offset_size(type, ns)*8; if(width>=0) { std::string result; for(; width!=0; --width) result+='x'; return result; } return ""; }
exprt dereference_rec( const exprt &src, const ssa_value_domaint &ssa_value_domain, const std::string &nondet_prefix, const namespacet &ns) { if(src.id()==ID_dereference) { const exprt &pointer=dereference_rec( to_dereference_expr(src).pointer(), ssa_value_domain, nondet_prefix, ns); const typet &pointed_type=ns.follow(pointer.type().subtype()); const ssa_value_domaint::valuest values=ssa_value_domain(pointer, ns); exprt result; if(values.value_set.empty()) { result=pointed_object(pointer, ns); } else { auto it=values.value_set.begin(); if(values.null || values.unknown || (values.value_set.size()>1 && it->type().get_bool("#dynamic"))) { std::string dyn_type_name=pointed_type.id_string(); if(pointed_type.id()==ID_struct) dyn_type_name+="_"+id2string(to_struct_type(pointed_type).get_tag()); irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown"; result=symbol_exprt(identifier, src.type()); result.set("#unknown_obj", true); } else { result=ssa_alias_value(src, (it++)->get_expr(), ns); result.set("#heap_access", result.type().get_bool("#dynamic")); } for(; it!=values.value_set.end(); ++it) { exprt guard=ssa_alias_guard(src, it->get_expr(), ns); exprt value=ssa_alias_value(src, it->get_expr(), ns); result=if_exprt(guard, value, result); result.set( "#heap_access", result.get_bool("#heap_access") || value.type().get_bool("#dynamic")); } } return result; } else if(src.id()==ID_member) { member_exprt tmp=to_member_expr(src); tmp.struct_op()= dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns); tmp.set("#heap_access", tmp.struct_op().get_bool("#heap_access")); #ifdef DEBUG std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n'; #endif if(tmp.struct_op().is_nil()) return nil_exprt(); return lift_if(tmp); } else if(src.id()==ID_address_of) { address_of_exprt tmp=to_address_of_expr(src); tmp.object()= dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns); tmp.set("#heap_access", tmp.object().get_bool("#heap_access")); if(tmp.object().is_nil()) return nil_exprt(); return lift_if(tmp); } else { exprt tmp=src; Forall_operands(it, tmp) { *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns); if(it->get_bool("#heap_access")) tmp.set("#heap_access", true); } return tmp; }
bool ssa_may_alias( const exprt &e1, const exprt &e2, const namespacet &ns) { #ifdef DEBUG std::cout << "MAY ALIAS1 " << from_expr(ns, "", e1) << " " << from_expr(ns, "", e2) << "\n"; #endif // The same? if(e1==e2) return true; // Both symbol? if(e1.id()==ID_symbol && e2.id()==ID_symbol) { return to_symbol_expr(e1).get_identifier()== to_symbol_expr(e2).get_identifier(); } // __CPROVER symbols if(e1.id()==ID_symbol && has_prefix( id2string(to_symbol_expr(e1).get_identifier()), CPROVER_PREFIX)) return false; if(e2.id()==ID_symbol && has_prefix( id2string(to_symbol_expr(e2).get_identifier()), CPROVER_PREFIX)) return false; if(e1.id()==ID_symbol && has_suffix( id2string(to_symbol_expr(e1).get_identifier()), "#return_value")) return false; if(e2.id()==ID_symbol && has_suffix( id2string(to_symbol_expr(e2).get_identifier()), "#return_value")) return false; // Both member? if(e1.id()==ID_member && e2.id()==ID_member) { const member_exprt &m1=to_member_expr(e1); const member_exprt &m2=to_member_expr(e2); // same component? if(m1.get_component_name()!=m2.get_component_name()) return false; return ssa_may_alias(m1.struct_op(), m2.struct_op(), ns); } // Both index? if(e1.id()==ID_index && e2.id()==ID_index) { const index_exprt &i1=to_index_expr(e1); const index_exprt &i2=to_index_expr(e2); return ssa_may_alias(i1.array(), i2.array(), ns); } const typet &t1=ns.follow(e1.type()); const typet &t2=ns.follow(e2.type()); // If one is an array and the other not, consider the elements if(t1.id()==ID_array && t2.id()!=ID_array) if(ssa_may_alias( index_exprt(e1, gen_zero(index_type()), t1.subtype()), e2, ns)) return true; if(t2.id()==ID_array && t2.id()!=ID_array) if(ssa_may_alias( e1, index_exprt(e2, gen_zero(index_type()), t2.subtype()), ns)) return true; // Pointers only alias with other pointers, // which is a restriction. if(t1.id()==ID_pointer) return t2.id()==ID_pointer; if(t2.id()==ID_pointer) return t1.id()==ID_pointer; // Is one a scalar pointer? if(e1.id()==ID_dereference && (t1.id()==ID_signedbv || t1.id()==ID_unsignedbv || t1.id()==ID_floatbv)) return true; if(e2.id()==ID_dereference && (t2.id()==ID_signedbv || t2.id()==ID_unsignedbv || t1.id()==ID_floatbv)) return true; // Is one a pointer? if(e1.id()==ID_dereference || e2.id()==ID_dereference) { // look at the types // same type? if(base_type_eq(t1, t2, ns)) { return true; } // should consider further options, e.g., struct prefixes return false; } return false; // both different objects }
void c_typecheck_baset::do_designated_initializer( exprt &result, designatort &designator, const exprt &value, bool force_constant) { assert(!designator.empty()); if(value.id()==ID_designated_initializer) { assert(value.operands().size()==1); designator= make_designator( designator.front().type, static_cast<const exprt &>(value.find(ID_designator))); assert(!designator.empty()); return do_designated_initializer( result, designator, value.op0(), force_constant); } exprt *dest=&result; // first phase: follow given designator for(size_t i=0; i<designator.size(); i++) { size_t index=designator[i].index; const typet &type=designator[i].type; const typet &full_type=follow(type); if(full_type.id()==ID_array || full_type.id()==ID_vector) { if(index>=dest->operands().size()) { if(full_type.id()==ID_array && (to_array_type(full_type).size().is_zero() || to_array_type(full_type).size().is_nil())) { // we are willing to grow an incomplete or zero-sized array exprt zero= zero_initializer( full_type.subtype(), value.source_location(), *this, get_message_handler()); dest->operands().resize(integer2size_t(index)+1, zero); // todo: adjust type! } else { err_location(value); error() << "array index designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } } dest=&(dest->operands()[integer2size_t(index)]); } else if(full_type.id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(full_type).components(); if(index>=dest->operands().size()) { err_location(value); error() << "structure member designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } assert(index<components.size()); assert(components[index].type().id()!=ID_code && !components[index].get_is_padding()); dest=&(dest->operands()[index]); } else if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); assert(index<components.size()); const union_typet::componentt &component=union_type.components()[index]; if(dest->id()==ID_union && dest->get(ID_component_name)==component.get_name()) { // Already right union component. We can initialize multiple submembers, // so do not overwrite this. } else { // Note that gcc issues a warning if the union component is switched. // Build a union expression from given component. union_exprt union_expr(type); union_expr.op()= zero_initializer( component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } dest=&(dest->op0()); } else assert(false); } // second phase: assign value // for this, we may need to go down, adding to the designator while(true) { // see what type we have to initialize const typet &type=designator.back().subtype; const typet &full_type=follow(type); assert(full_type.id()!=ID_symbol); // do we initialize a scalar? if(full_type.id()!=ID_struct && full_type.id()!=ID_union && full_type.id()!=ID_array && full_type.id()!=ID_vector) { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.id()==ID_initializer_list && value.operands().size()==1) *dest=do_initializer_rec(value.op0(), type, force_constant); else *dest=do_initializer_rec(value, type, force_constant); assert(full_type==follow(dest->type())); return; // done } // union? The component in the zero initializer might // not be the first one. if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); if(!components.empty()) { const union_typet::componentt &component= union_type.components().front(); union_exprt union_expr(type); union_expr.op()= zero_initializer( component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } } // see what initializer we are given if(value.id()==ID_initializer_list) { *dest=do_initializer_rec(value, type, force_constant); return; // done } else if(value.id()==ID_string_constant) { // We stop for initializers that are string-constants, // which are like arrays. We only do so if we are to // initialize an array of scalars. if(full_type.id()==ID_array && (follow(full_type.subtype()).id()==ID_signedbv || follow(full_type.subtype()).id()==ID_unsignedbv)) { *dest=do_initializer_rec(value, type, force_constant); return; // done } } else if(follow(value.type())==full_type) { // a struct/union/vector can be initialized directly with // an expression of the right type. This doesn't // work with arrays, unfortunately. if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { *dest=value; return; // done } } assert(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_array || full_type.id()==ID_vector); // we are initializing a compound type, and enter it! // this may change the type, full_type might not be valid anymore const typet dest_type=full_type; designator_enter(type, designator); if(dest->operands().empty()) { err_location(value); error() << "cannot initialize type `" << to_string(dest_type) << "' using value `" << to_string(value) << "'" << eom; throw 0; } dest=&(dest->op0()); // we run into another loop iteration } }
exprt build_full_lhs_rec( const prop_convt &prop_conv, const namespacet &ns, const exprt &src_original, // original identifiers const exprt &src_ssa) // renamed identifiers { if(src_ssa.id()!=src_original.id()) return src_original; const irep_idt id=src_original.id(); if(id==ID_index) { // get index value from src_ssa exprt index_value=prop_conv.get(to_index_expr(src_ssa).index()); if(index_value.is_not_nil()) { simplify(index_value, ns); index_exprt tmp=to_index_expr(src_original); tmp.index()=index_value; tmp.array()= build_full_lhs_rec(prop_conv, ns, to_index_expr(src_original).array(), to_index_expr(src_ssa).array()); return tmp; } return src_original; } else if(id==ID_member) { member_exprt tmp=to_member_expr(src_original); tmp.struct_op()=build_full_lhs_rec( prop_conv, ns, to_member_expr(src_original).struct_op(), to_member_expr(src_ssa).struct_op()); } else if(id==ID_if) { if_exprt tmp2=to_if_expr(src_original); tmp2.false_case()=build_full_lhs_rec(prop_conv, ns, tmp2.false_case(), to_if_expr(src_ssa).false_case()); tmp2.true_case()=build_full_lhs_rec(prop_conv, ns, tmp2.true_case(), to_if_expr(src_ssa).true_case()); exprt tmp=prop_conv.get(to_if_expr(src_ssa).cond()); if(tmp.is_true()) return tmp2.true_case(); else if(tmp.is_false()) return tmp2.false_case(); else return tmp2; } else if(id==ID_typecast) { typecast_exprt tmp=to_typecast_expr(src_original); tmp.op()=build_full_lhs_rec(prop_conv, ns, to_typecast_expr(src_original).op(), to_typecast_expr(src_ssa).op()); return tmp; } else if(id==ID_byte_extract_little_endian || id==ID_byte_extract_big_endian) { exprt tmp=src_original; assert(tmp.operands().size()==2); tmp.op0()=build_full_lhs_rec(prop_conv, ns, tmp.op0(), src_ssa.op0()); // re-write into big case-split } return src_original; }
exprt c_typecheck_baset::do_initializer_rec( const exprt &value, const typet &type, bool force_constant) { const typet &full_type=follow(type); if(full_type.id()==ID_incomplete_struct) { err_location(value); error() << "type `" << to_string(full_type) << "' is still incomplete -- cannot initialize" << eom; throw 0; } if(value.id()==ID_initializer_list) return do_initializer_list(value, type, force_constant); if(value.id()==ID_array && value.get_bool(ID_C_string_constant) && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==value.type().subtype().get(ID_width)) { exprt tmp=value; // adjust char type tmp.type().subtype()=full_type.subtype(); Forall_operands(it, tmp) it->type()=full_type.subtype(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp.operands().resize(integer2size_t(array_size)); tmp.type()=type; } else if(mp_integer(tmp.operands().size())<array_size) { // fill up tmp.type()=type; exprt zero= zero_initializer( full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp.operands().resize(integer2size_t(array_size), zero); } } return tmp; } if(value.id()==ID_string_constant && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { // will go away, to be replaced by the above block string_constantt tmp1=to_string_constant(value); // adjust char type tmp1.type().subtype()=full_type.subtype(); exprt tmp2=tmp1.to_array_expr(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp2.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp2.operands().resize(integer2size_t(array_size)); tmp2.type()=type; } else if(mp_integer(tmp2.operands().size())<array_size) { // fill up tmp2.type()=type; exprt zero= zero_initializer( full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp2.operands().resize(integer2size_t(array_size), zero); } } return tmp2; } if(full_type.id()==ID_array && to_array_type(full_type).size().is_nil()) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with `" << to_string(value) << "'" << eom; throw 0; } if(value.id()==ID_designated_initializer) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with designated initializer" << eom; throw 0; } exprt result=value; implicit_typecast(result, type); return result; }