void c_typecheck_baset::typecheck_asm(codet &code) { const irep_idt flavor=to_code_asm(code).get_flavor(); if(flavor==ID_gcc) { // These have 5 operands. // The first parameter is a string. // Parameters 1, 2, 3, 4 are lists of expressions. // Parameter 1: OutputOperands // Parameter 2: InputOperands // Parameter 3: Clobbers // Parameter 4: GotoLabels assert(code.operands().size()==5); typecheck_expr(code.op0()); for(unsigned i=1; i<code.operands().size(); i++) { exprt &list=code.operands()[i]; Forall_operands(it, list) typecheck_expr(*it); } } else if(flavor==ID_msc) { assert(code.operands().size()==1); typecheck_expr(code.op0()); } }
void goto_convertt::convert_try_catch( const codet &code, goto_programt &dest) { assert(code.operands().size()>=2); // add the CATCH-push instruction to 'dest' goto_programt::targett catch_push_instruction=dest.add_instruction(); catch_push_instruction->make_catch(); catch_push_instruction->code.set_statement(ID_catch); catch_push_instruction->source_location=code.source_location(); // the CATCH-push instruction is annotated with a list of IDs, // one per target irept::subt &exception_list= catch_push_instruction->code.add(ID_exception_list).get_sub(); // add a SKIP target for the end of everything goto_programt end; goto_programt::targett end_target=end.add_instruction(); end_target->make_skip(); // the first operand is the 'try' block convert(to_code(code.op0()), dest); // add the CATCH-pop to the end of the 'try' block goto_programt::targett catch_pop_instruction=dest.add_instruction(); catch_pop_instruction->make_catch(); catch_pop_instruction->code.set_statement(ID_catch); // add a goto to the end of the 'try' block dest.add_instruction()->make_goto(end_target); for(unsigned i=1; i<code.operands().size(); i++) { const codet &block=to_code(code.operands()[i]); // grab the ID and add to CATCH instruction exception_list.push_back(irept(block.get(ID_exception_id))); goto_programt tmp; convert(block, tmp); catch_push_instruction->targets.push_back(tmp.instructions.begin()); dest.destructive_append(tmp); // add a goto to the end of the 'catch' block dest.add_instruction()->make_goto(end_target); } // add the end-target dest.destructive_append(end); }
void goto_convertt::convert_CPROVER_try_catch( const codet &code, goto_programt &dest) { if(code.operands().size()!=2) { err_location(code); throw "CPROVER_try_catch expects two arguments"; } // this is where we go after 'throw' goto_programt tmp; tmp.add_instruction(SKIP)->source_location=code.source_location(); // set 'throw' target throw_targett throw_target(targets); targets.set_throw(tmp.instructions.begin()); // now put 'catch' code onto destructor stack code_ifthenelset catch_code; catch_code.cond()=exception_flag(); catch_code.add_source_location()=code.source_location(); catch_code.then_case()=to_code(code.op1()); targets.destructor_stack.push_back(catch_code); // now convert 'try' code convert(to_code(code.op0()), dest); // pop 'catch' code off stack targets.destructor_stack.pop_back(); // add 'throw' target dest.destructive_append(tmp); }
void java_bytecode_typecheckt::typecheck_code(codet &code) { const irep_idt &statement=code.get_statement(); if(statement==ID_assign) { code_assignt &code_assign=to_code_assign(code); typecheck_expr(code_assign.lhs()); typecheck_expr(code_assign.rhs()); if(code_assign.lhs().type()!=code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); } else if(statement==ID_block) { Forall_operands(it, code) typecheck_code(to_code(*it)); } else if(statement==ID_label) { code_labelt &code_label=to_code_label(code); typecheck_code(code_label.code()); } else if(statement==ID_goto) { } else if(statement==ID_ifthenelse) { code_ifthenelset &code_ifthenelse=to_code_ifthenelse(code); typecheck_expr(code_ifthenelse.cond()); typecheck_code(code_ifthenelse.then_case()); if(code_ifthenelse.else_case().is_not_nil()) typecheck_code(code_ifthenelse.else_case()); } else if(statement==ID_switch) { code_switcht &code_switch = to_code_switch(code); typecheck_expr(code_switch.value()); } else if(statement==ID_return) { if(code.operands().size()==1) typecheck_expr(code.op0()); } else if(statement==ID_function_call) { code_function_callt &code_function_call=to_code_function_call(code); typecheck_expr(code_function_call.lhs()); typecheck_expr(code_function_call.function()); for(code_function_callt::argumentst::iterator a_it=code_function_call.arguments().begin(); a_it!=code_function_call.arguments().end(); a_it++) typecheck_expr(*a_it); } }
void rw_sett::compute(const codet &code) { const irep_idt &statement=code.get_statement(); if(statement==ID_assign) { assert(code.operands().size()==2); assign(code.op0(), code.op1()); } }
void c_typecheck_baset::typecheck_start_thread(codet &code) { if(code.operands().size()!=1) { err_location(code); error() << "start_thread expected to have one operand" << eom; throw 0; } typecheck_code(to_code(code.op0())); }
void goto_convertt::convert_java_try_catch( const codet &code, goto_programt &dest) { assert(!code.operands().empty()); // add the CATCH instruction to 'dest' goto_programt::targett catch_instruction=dest.add_instruction(); catch_instruction->make_catch(); catch_instruction->code.set_statement(ID_catch); catch_instruction->source_location=code.source_location(); catch_instruction->function=code.source_location().get_function(); // the CATCH instruction is annotated with a list of exception IDs const irept exceptions=code.op0().find(ID_exception_list); if(exceptions.is_not_nil()) { irept::subt exceptions_sub=exceptions.get_sub(); irept::subt &exception_list= catch_instruction->code.add(ID_exception_list).get_sub(); exception_list.resize(exceptions_sub.size()); for(size_t i=0; i<exceptions_sub.size(); ++i) exception_list[i].id(exceptions_sub[i].id()); } // the CATCH instruction is also annotated with a list of handle labels const irept handlers=code.op0().find(ID_label); if(handlers.is_not_nil()) { irept::subt handlers_sub=handlers.get_sub(); irept::subt &handlers_list= catch_instruction->code.add(ID_label).get_sub(); handlers_list.resize(handlers_sub.size()); for(size_t i=0; i<handlers_sub.size(); ++i) handlers_list[i].id(handlers_sub[i].id()); } // the CATCH instruction may also signal a handler if(code.op0().has_operands()) { catch_instruction->code.get_sub().resize(1); catch_instruction->code.get_sub()[0]=code.op0().op0(); } // add a SKIP target for the end of everything goto_programt end; goto_programt::targett end_target=end.add_instruction(); end_target->make_skip(); end_target->source_location=code.source_location(); end_target->function=code.source_location().get_function(); // add the end-target dest.destructive_append(end); }
void c_typecheck_baset::typecheck_return(codet &code) { if(code.operands().empty()) { if(follow(return_type).id()!=ID_empty) { // gcc doesn't actually complain, it just warns! // We'll put a zero here, which is dubious. exprt zero=zero_initializer(return_type, code.source_location(), *this, get_message_handler()); code.copy_to_operands(zero); } } else if(code.operands().size()==1) { typecheck_expr(code.op0()); if(follow(return_type).id()==ID_empty) { // gcc doesn't actually complain, it just warns! if(follow(code.op0().type()).id()!=ID_empty) { warning().source_location=code.source_location(); warning() << "function has return void "; warning() << "but a return statement returning "; warning() << to_string(follow(code.op0().type())); warning() << eom; code.op0().make_typecast(return_type); } } else implicit_typecast(code.op0(), return_type); } else { err_location(code); error() << "return expected to have 0 or 1 operands" << eom; throw 0; } }
void c_typecheck_baset::typecheck_expression(codet &code) { if(code.operands().size()!=1) { err_location(code); error() << "expression statement expected to have one operand" << eom; throw 0; } exprt &op=code.op0(); typecheck_expr(op); }
void goto_convertt::convert_msc_try_except( const codet &code, goto_programt &dest) { if(code.operands().size()!=3) { err_location(code); throw "msc_try_except expects three arguments"; } convert(to_code(code.op0()), dest); // todo: generate exception tracking }
void c_typecheck_baset::typecheck_block(codet &code) { Forall_operands(it, code) typecheck_code(to_code(*it)); // do decl-blocks exprt new_ops; new_ops.operands().reserve(code.operands().size()); Forall_operands(it1, code) { if(it1->is_nil()) continue; codet &code_op=to_code(*it1); if(code_op.get_statement()==ID_label) { // these may be nested codet *code_ptr=&code_op; while(code_ptr->get_statement()==ID_label) { assert(code_ptr->operands().size()==1); code_ptr=&to_code(code_ptr->op0()); } //codet &label_op=*code_ptr; new_ops.move_to_operands(code_op); } else new_ops.move_to_operands(code_op); } code.operands().swap(new_ops.operands()); }
void goto_convertt::convert_msc_try_except( const codet &code, goto_programt &dest) { if(code.operands().size()!=3) { error().source_location=code.find_source_location(); error() << "msc_try_except expects three arguments" << eom; throw 0; } convert(to_code(code.op0()), dest); // todo: generate exception tracking }
void c_typecheck_baset::typecheck_assign(codet &code) { if(code.operands().size()!=2) { err_location(code); error() << "assignment statement expected to have two operands" << eom; throw 0; } typecheck_expr(code.op0()); typecheck_expr(code.op1()); implicit_typecast(code.op1(), code.op0().type()); }
void jsil_typecheckt::typecheck_code(codet &code) { const irep_idt &statement=code.get_statement(); if(statement==ID_function_call) typecheck_function_call(to_code_function_call(code)); else if(statement==ID_return) typecheck_return(to_code_return(code)); else if(statement==ID_expression) { if(code.operands().size()!=1) throw "expression statement expected to have one operand"; typecheck_expr(code.op0()); } else if(statement==ID_label) { typecheck_code(to_code_label(code).code()); // TODO: produce defined label set } else if(statement==ID_block) typecheck_block(code); else if(statement==ID_ifthenelse) typecheck_ifthenelse(to_code_ifthenelse(code)); else if(statement==ID_goto) { // TODO: produce used label set } else if(statement==ID_assign) typecheck_assign(to_code_assign(code)); else if(statement==ID_try_catch) typecheck_try_catch(to_code_try_catch(code)); else if(statement==ID_skip) { } else { err_location(code); error() << "unexpected statement: " << statement << eom; throw 0; } }
void goto_convertt::convert_CPROVER_try_finally( const codet &code, goto_programt &dest) { if(code.operands().size()!=2) { err_location(code); throw "CPROVER_try_finally expects two arguments"; } // first put 'finally' code onto destructor stack targets.destructor_stack.push_back(to_code(code.op1())); // do 'try' code convert(to_code(code.op0()), dest); // pop 'finally' from destructor stack targets.destructor_stack.pop_back(); // now add 'finally' code convert(to_code(code.op1()), dest); }
void goto_convertt::convert_msc_try_finally( const codet &code, goto_programt &dest) { if(code.operands().size()!=2) { error().source_location=code.find_source_location(); error() << "msc_try_finally expects two arguments" << eom; throw 0; } goto_programt tmp; tmp.add_instruction(SKIP)->source_location=code.source_location(); { // save 'leave' target leave_targett leave_target(targets); targets.set_leave(tmp.instructions.begin()); // first put 'finally' code onto destructor stack targets.destructor_stack.push_back(to_code(code.op1())); // do 'try' code convert(to_code(code.op0()), dest); // pop 'finally' from destructor stack targets.destructor_stack.pop_back(); // 'leave' target gets restored here } // now add 'finally' code convert(to_code(code.op1()), dest); // this is the target for 'leave' dest.destructive_append(tmp); }
void c_typecheck_baset::typecheck_gcc_computed_goto(codet &code) { if(code.operands().size()!=1) { err_location(code); error() << "computed-goto expected to have one operand" << eom; throw 0; } exprt &dest=code.op0(); if(dest.id()!=ID_dereference) { err_location(dest); error() << "computed-goto expected to have dereferencing operand" << eom; throw 0; } assert(dest.operands().size()==1); typecheck_expr(dest.op0()); dest.type()=empty_typet(); }
void c_typecheck_baset::typecheck_gcc_switch_case_range(codet &code) { if(code.operands().size()!=3) { err_location(code); error() << "gcc_switch_case_range expected to have three operands" << eom; throw 0; } typecheck_code(to_code(code.op2())); if(!case_is_allowed) { err_location(code); error() << "did not expect `case' here" << eom; throw 0; } typecheck_expr(code.op0()); typecheck_expr(code.op1()); implicit_typecast(code.op0(), switch_op_type); implicit_typecast(code.op1(), switch_op_type); }
void c_typecheck_baset::typecheck_decl(codet &code) { // this comes with 1 operand, which is a declaration if(code.operands().size()!=1) { err_location(code); error() << "decl expected to have 1 operand" << eom; throw 0; } // op0 must be declaration if(code.op0().id()!=ID_declaration) { err_location(code); error() << "decl statement expected to have declaration as operand" << eom; throw 0; } ansi_c_declarationt declaration; declaration.swap(code.op0()); if(declaration.get_is_static_assert()) { assert(declaration.operands().size()==2); codet new_code(ID_static_assert); new_code.add_source_location()=code.source_location(); new_code.operands().swap(declaration.operands()); code.swap(new_code); typecheck_code(code); return; // done } typecheck_declaration(declaration); std::list<codet> new_code; // iterate over declarators for(ansi_c_declarationt::declaratorst::const_iterator d_it=declaration.declarators().begin(); d_it!=declaration.declarators().end(); d_it++) { irep_idt identifier=d_it->get_name(); // look it up symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) { err_location(code); error() << "failed to find decl symbol `" << identifier << "' in symbol table" << eom; throw 0; } symbolt &symbol=s_it->second; // This must not be an incomplete type, unless it's 'extern' // or a typedef. if(!symbol.is_type && !symbol.is_extern && !is_complete_type(symbol.type)) { error().source_location=symbol.location; error() << "incomplete type not permitted here" << eom; throw 0; } // see if it's a typedef // or a function // or static if(symbol.is_type || symbol.type.id()==ID_code || symbol.is_static_lifetime) { // we ignore } else { code_declt code; code.add_source_location()=symbol.location; code.symbol()=symbol.symbol_expr(); code.symbol().add_source_location()=symbol.location; // add initializer, if any if(symbol.value.is_not_nil()) { code.operands().resize(2); code.op1()=symbol.value; } new_code.push_back(code); } } // stash away any side-effects in the declaration new_code.splice(new_code.begin(), clean_code); if(new_code.empty()) { source_locationt source_location=code.source_location(); code=code_skipt(); code.add_source_location()=source_location; } else if(new_code.size()==1) { code.swap(new_code.front()); } else { // build a decl-block code_blockt code_block(new_code); code_block.set_statement(ID_decl_block); code.swap(code_block); } }
void c_typecheck_baset::typecheck_code(codet &code) { if(code.id()!=ID_code) { err_location(code); error() << "expected code, got " << code.pretty() << eom; throw 0; } code.type()=code_typet(); const irep_idt &statement=code.get_statement(); if(statement==ID_expression) typecheck_expression(code); else if(statement==ID_label) typecheck_label(to_code_label(code)); else if(statement==ID_switch_case) typecheck_switch_case(to_code_switch_case(code)); else if(statement==ID_gcc_switch_case_range) typecheck_gcc_switch_case_range(code); else if(statement==ID_block) typecheck_block(code); else if(statement==ID_decl_block) { } else if(statement==ID_ifthenelse) typecheck_ifthenelse(to_code_ifthenelse(code)); else if(statement==ID_while) typecheck_while(to_code_while(code)); else if(statement==ID_dowhile) typecheck_dowhile(to_code_dowhile(code)); else if(statement==ID_for) typecheck_for(code); else if(statement==ID_switch) typecheck_switch(to_code_switch(code)); else if(statement==ID_break) typecheck_break(code); else if(statement==ID_goto) typecheck_goto(to_code_goto(code)); else if(statement==ID_gcc_computed_goto) typecheck_gcc_computed_goto(code); else if(statement==ID_continue) typecheck_continue(code); else if(statement==ID_return) typecheck_return(code); else if(statement==ID_decl) typecheck_decl(code); else if(statement==ID_assign) typecheck_assign(code); else if(statement==ID_skip) { } else if(statement==ID_asm) typecheck_asm(code); else if(statement==ID_start_thread) typecheck_start_thread(code); else if(statement==ID_gcc_local_label) typecheck_gcc_local_label(code); else if(statement==ID_msc_try_finally) { assert(code.operands().size()==2); typecheck_code(to_code(code.op0())); typecheck_code(to_code(code.op1())); } else if(statement==ID_msc_try_except) { assert(code.operands().size()==3); typecheck_code(to_code(code.op0())); typecheck_expr(code.op1()); typecheck_code(to_code(code.op2())); } else if(statement==ID_msc_leave) { // fine as is, but should check that we // are in a 'try' block } else if(statement==ID_static_assert) { assert(code.operands().size()==2); typecheck_expr(code.op0()); typecheck_expr(code.op1()); } else if(statement==ID_CPROVER_try_catch || statement==ID_CPROVER_try_finally) { assert(code.operands().size()==2); typecheck_code(to_code(code.op0())); typecheck_code(to_code(code.op1())); } else if(statement==ID_CPROVER_throw) { assert(code.operands().empty()); } else if(statement==ID_assume || statement==ID_assert) { // These are not generated by the C/C++ parsers, // but we allow them for the benefit of other users // of the typechecker. assert(code.operands().size()==1); typecheck_expr(code.op0()); } else { err_location(code); error() << "unexpected statement: " << statement << eom; throw 0; } }
void c_typecheck_baset::typecheck_for(codet &code) { if(code.operands().size()!=4) { err_location(code); error() << "for expected to have four operands" << eom; throw 0; } // the "for" statement has an implicit block around it, // since code.op0() may contain declarations // // we therefore transform // // for(a;b;c) d; // // to // // { a; for(;b;c) d; } // // if config.ansi_c.for_has_scope if(!config.ansi_c.for_has_scope || code.op0().is_nil()) { if(code.op0().is_not_nil()) typecheck_code(to_code(code.op0())); if(code.op1().is_nil()) code.op1()=true_exprt(); else { typecheck_expr(code.op1()); implicit_typecast_bool(code.op1()); } if(code.op2().is_not_nil()) typecheck_expr(code.op2()); if(code.op3().is_not_nil()) { // save & set flags bool old_break_is_allowed=break_is_allowed; bool old_continue_is_allowed=continue_is_allowed; break_is_allowed=continue_is_allowed=true; // recursive call if(to_code(code.op3()).get_statement()==ID_decl_block) { code_blockt code_block; code_block.add_source_location()=code.op3().source_location(); code_block.move_to_operands(code.op3()); code.op3().swap(code_block); } typecheck_code(to_code(code.op3())); // restore flags break_is_allowed=old_break_is_allowed; continue_is_allowed=old_continue_is_allowed; } } else { code_blockt code_block; code_block.add_source_location()=code.source_location(); if(to_code(code.op3()).get_statement()==ID_block) code_block.set( ID_C_end_location, to_code_block(to_code(code.op3())).end_location()); else code_block.set( ID_C_end_location, code.op3().source_location());; code_block.reserve_operands(2); code_block.move_to_operands(code.op0()); code.op0().make_nil(); code_block.move_to_operands(code); code.swap(code_block); typecheck_code(code); // recursive call } typecheck_spec_expr(code, ID_C_spec_loop_invariant); }