void goto_convertt::do_cpp_new( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_cpp_new without lhs is yet to be implemented"; // build size expression exprt object_size= static_cast<const exprt &>(rhs.find(ID_sizeof)); bool new_array=rhs.get(ID_statement)==ID_cpp_new_array; exprt count; if(new_array) { count=static_cast<const exprt &>(rhs.find(ID_size)); if(count.type()!=object_size.type()) count.make_typecast(object_size.type()); // might have side-effect clean_expr(count, dest); } exprt tmp_symbol_expr; // is this a placement new? if(rhs.operands().empty()) // no, "regular" one { // call __new or __new_array exprt new_symbol= ns.lookup(new_array?"__new_array":"__new").symbol_expr(); const code_typet &code_type= to_code_type(new_symbol.type()); const typet &return_type= code_type.return_type(); assert(code_type.parameters().size()==1 || code_type.parameters().size()==2); const symbolt &tmp_symbol= new_tmp_symbol(return_type, "new", dest, rhs.source_location()); tmp_symbol_expr=tmp_symbol.symbol_expr(); code_function_callt new_call; new_call.function()=new_symbol; if(new_array) new_call.arguments().push_back(count); new_call.arguments().push_back(object_size); new_call.set("#type", lhs.type().subtype()); new_call.lhs()=tmp_symbol_expr; new_call.add_source_location()=rhs.source_location(); convert(new_call, dest); } else if(rhs.operands().size()==1) { // call __placement_new exprt new_symbol= ns.lookup(new_array?"__placement_new_array":"__placement_new").symbol_expr(); const code_typet &code_type= to_code_type(new_symbol.type()); const typet &return_type=code_type.return_type(); assert(code_type.parameters().size()==2 || code_type.parameters().size()==3); const symbolt &tmp_symbol= new_tmp_symbol(return_type, "new", dest, rhs.source_location()); tmp_symbol_expr=tmp_symbol.symbol_expr(); code_function_callt new_call; new_call.function()=new_symbol; if(new_array) new_call.arguments().push_back(count); new_call.arguments().push_back(object_size); new_call.arguments().push_back(rhs.op0()); // memory location new_call.set("#type", lhs.type().subtype()); new_call.lhs()=tmp_symbol_expr; new_call.add_source_location()=rhs.source_location(); for(unsigned i=0; i<code_type.parameters().size(); i++) if(new_call.arguments()[i].type()!=code_type.parameters()[i].type()) new_call.arguments()[i].make_typecast(code_type.parameters()[i].type()); convert(new_call, dest); } else throw "cpp_new expected to have 0 or 1 operands"; goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt( lhs, typecast_exprt(tmp_symbol_expr, lhs.type())); t_n->source_location=rhs.find_source_location(); // grab initializer goto_programt tmp_initializer; cpp_new_initializer(lhs, rhs, tmp_initializer); dest.destructive_append(tmp_initializer); }
void goto_convertt::clean_expr( exprt &expr, goto_programt &dest, bool result_is_used) { // this cleans: // && || ?: comma (control-dependency) // function calls // object constructors like arrays, string constants, structs // ++ -- // compound assignments // compound literals if(!needs_cleaning(expr)) return; if(expr.id()==ID_and || expr.id()==ID_or) { // rewrite into ?: rewrite_boolean(expr); // recursive call clean_expr(expr, dest, result_is_used); return; } else if(expr.id()==ID_if) { // first clean condition clean_expr(to_if_expr(expr).cond(), dest, true); // possibly done now if(!needs_cleaning(to_if_expr(expr).true_case()) && !needs_cleaning(to_if_expr(expr).false_case())) return; // copy expression if_exprt if_expr=to_if_expr(expr); if(!if_expr.cond().is_boolean()) throw "first argument of `if' must be boolean, but got " +if_expr.cond().to_string(); const locationt location=expr.find_location(); // We do some constant-folding here, to mimic // what typical compilers do. { exprt tmp_cond=if_expr.cond(); simplify(tmp_cond, ns); if(tmp_cond.is_true()) { clean_expr(if_expr.true_case(), dest, result_is_used); expr=if_expr.true_case(); return; } else if(tmp_cond.is_false()) { clean_expr(if_expr.false_case(), dest, result_is_used); expr=if_expr.false_case(); return; } } goto_programt tmp_true; clean_expr(if_expr.true_case(), tmp_true, result_is_used); goto_programt tmp_false; clean_expr(if_expr.false_case(), tmp_false, result_is_used); if(result_is_used) { symbolt &new_symbol= new_tmp_symbol(expr.type(), "if_expr", dest, location); code_assignt assignment_true; assignment_true.lhs()=new_symbol.symbol_expr(); assignment_true.rhs()=if_expr.true_case(); assignment_true.location()=location; convert(assignment_true, tmp_true); code_assignt assignment_false; assignment_false.lhs()=new_symbol.symbol_expr(); assignment_false.rhs()=if_expr.false_case(); assignment_false.location()=location; convert(assignment_false, tmp_false); // overwrites expr expr=new_symbol.symbol_expr(); } else { // preserve the expressions for possible later checks if(if_expr.true_case().is_not_nil()) { code_expressiont code_expression(if_expr.true_case()); convert(code_expression, tmp_true); } if(if_expr.false_case().is_not_nil()) { code_expressiont code_expression(if_expr.false_case()); convert(code_expression, tmp_false); } expr=nil_exprt(); } // generate guard for argument side-effects generate_ifthenelse( if_expr.cond(), tmp_true, tmp_false, location, dest); return; } else if(expr.id()==ID_comma) { if(result_is_used) { exprt result; Forall_operands(it, expr) { bool last=(it==--expr.operands().end()); // special treatment for last one if(last) { result.swap(*it); clean_expr(result, dest, true); } else { clean_expr(*it, dest, false); // remember these for later checks if(it->is_not_nil()) convert(code_expressiont(*it), dest); } } expr.swap(result); } else // result not used {