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 jsil_typecheckt::typecheck_ifthenelse(code_ifthenelset &code) { exprt &cond=code.cond(); typecheck_expr(cond); make_type_compatible(cond, bool_typet(), true); typecheck_code(to_code(code.then_case())); if(!code.else_case().is_nil()) typecheck_code(to_code(code.else_case())); }
void c_typecheck_baset::typecheck_ifthenelse(code_ifthenelset &code) { if(code.operands().size()!=3) { err_location(code); error() << "ifthenelse expected to have three operands" << eom; throw 0; } exprt &cond=code.cond(); typecheck_expr(cond); #if 0 if(cond.id()==ID_sideeffect && cond.get(ID_statement)==ID_assign) { warning("warning: assignment in if condition"); } #endif implicit_typecast_bool(cond); if(to_code(code.then_case()).get_statement()==ID_decl_block) { code_blockt code_block; code_block.add_source_location()=code.then_case().source_location(); code_block.move_to_operands(code.then_case()); code.then_case().swap(code_block); } typecheck_code(to_code(code.then_case())); if(!code.else_case().is_nil()) { if(to_code(code.else_case()).get_statement()==ID_decl_block) { code_blockt code_block; code_block.add_source_location()=code.else_case().source_location(); code_block.move_to_operands(code.else_case()); code.else_case().swap(code_block); } typecheck_code(to_code(code.else_case())); } }
void c_typecheck_baset::typecheck_switch(code_switcht &code) { if(code.operands().size()!=2) { err_location(code); error() << "switch expects two operands" << eom; throw 0; } typecheck_expr(code.value()); // this needs to be promoted implicit_typecast_arithmetic(code.value()); // save & set flags bool old_case_is_allowed(case_is_allowed); bool old_break_is_allowed(break_is_allowed); typet old_switch_op_type(switch_op_type); switch_op_type=code.value().type(); break_is_allowed=case_is_allowed=true; typecheck_code(code.body()); // restore flags case_is_allowed=old_case_is_allowed; break_is_allowed=old_break_is_allowed; switch_op_type=old_switch_op_type; }
void c_typecheck_baset::typecheck_switch_case(code_switch_caset &code) { if(code.operands().size()!=2) { err_location(code); error() << "switch_case expected to have two operands" << eom; throw 0; } typecheck_code(code.code()); if(code.is_default()) { if(!case_is_allowed) { err_location(code); error() << "did not expect default label here" << eom; throw 0; } } else { if(!case_is_allowed) { err_location(code); error() << "did not expect `case' here" << eom; throw 0; } exprt &case_expr=code.case_op(); typecheck_expr(case_expr); implicit_typecast(case_expr, switch_op_type); } }
void c_typecheck_baset::typecheck_label(code_labelt &code) { // record the label labels_defined[code.get_label()]=code.source_location(); typecheck_code(code.code()); }
void c_typecheck_baset::typecheck_while(code_whilet &code) { if(code.operands().size()!=2) { err_location(code); error() << "while expected to have two operands" << eom; throw 0; } typecheck_expr(code.cond()); implicit_typecast_bool(code.cond()); // 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; if(code.body().get_statement()==ID_decl_block) { code_blockt code_block; code_block.add_source_location()=code.body().source_location(); code_block.move_to_operands(code.body()); code.body().swap(code_block); } typecheck_code(code.body()); // restore flags break_is_allowed=old_break_is_allowed; continue_is_allowed=old_continue_is_allowed; typecheck_spec_expr(code, ID_C_spec_loop_invariant); }
void jsil_typecheckt::typecheck_non_type_symbol(symbolt &symbol) { assert(!symbol.is_type); // Using is_extern to check if symbol was already typechecked if(symbol.is_extern) return; if(symbol.value.id()!="no-body-just-yet") symbol.is_extern=true; proc_name=symbol.name; typecheck_type(symbol.type); if(symbol.value.id()==ID_code) typecheck_code(to_code(symbol.value)); else if(symbol.name=="eval") { // No code for eval. Do nothing } else if(symbol.value.id()=="no-body-just-yet") { // Do nothing } else throw "Non type symbol value expected code, but got "+ symbol.value.pretty(); }
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 jsil_typecheckt::typecheck_try_catch(code_try_catcht &code) { // A special case of try catch with one catch clause if(code.operands().size()!=3) throw "try_catch expected to have three operands"; // function call typecheck_function_call(to_code_function_call(code.try_code())); // catch decl is not used, but is required by goto-programs typecheck_code(code.get_catch_code(0)); }
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 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 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 cpp_typecheckt::convert_function(symbolt &symbol) { code_typet &function_type= to_code_type(template_subtype(symbol.type)); // only a prototype? if(symbol.value.is_nil()) return; // if it is a destructor, add the implicit code if(symbol.type.get(ID_return_type)==ID_destructor) { const symbolt &msymb=lookup(symbol.type.get(ID_C_member_name)); assert(symbol.value.id()==ID_code); assert(symbol.value.get(ID_statement)==ID_block); symbol.value.copy_to_operands(dtor(msymb)); } // enter appropriate scope cpp_save_scopet saved_scope(cpp_scopes); cpp_scopet &function_scope=cpp_scopes.set_scope(symbol.name); // fix the scope's prefix function_scope.prefix+=id2string(symbol.name)+"::"; // genuine function definition -- do the parameter declarations convert_arguments(symbol.mode, function_type); // create "this" if it's a non-static method if(function_scope.is_method && !function_scope.is_static_member) { code_typet::argumentst &arguments=function_type.arguments(); assert(arguments.size()>=1); code_typet::argumentt &this_argument_expr=arguments.front(); function_scope.this_expr=exprt(ID_symbol, this_argument_expr.type()); function_scope.this_expr.set(ID_identifier, this_argument_expr.get(ID_C_identifier)); } else function_scope.this_expr.make_nil(); // do the function body start_typecheck_code(); // save current return type typet old_return_type=return_type; return_type=function_type.return_type(); // constructor, destructor? if(return_type.id()==ID_constructor || return_type.id()==ID_destructor) return_type=empty_typet(); typecheck_code(to_code(symbol.value)); symbol.value.type()=symbol.type; return_type = old_return_type; }
void c_typecheck_baset::typecheck_function_body(symbolt &symbol) { code_typet &code_type=to_code_type(symbol.type); assert(symbol.value.is_not_nil()); // reset labels labels_used.clear(); labels_defined.clear(); // fix type symbol.value.type()=code_type; // set return type return_type=code_type.return_type(); unsigned anon_counter=0; // Add the parameter declarations into the symbol table. code_typet::parameterst ¶meters=code_type.parameters(); for(code_typet::parameterst::iterator p_it=parameters.begin(); p_it!=parameters.end(); p_it++) { // may be anonymous if(p_it->get_base_name()==irep_idt()) { irep_idt base_name="#anon"+i2string(anon_counter++); p_it->set_base_name(base_name); } // produce identifier irep_idt base_name=p_it->get_base_name(); irep_idt identifier=id2string(symbol.name)+"::"+id2string(base_name); p_it->set_identifier(identifier); parameter_symbolt p_symbol; p_symbol.type=p_it->type(); p_symbol.name=identifier; p_symbol.base_name=base_name; p_symbol.location=p_it->source_location(); symbolt *new_p_symbol; move_symbol(p_symbol, new_p_symbol); } // typecheck the body code typecheck_code(to_code(symbol.value)); // special case for main() if(symbol.name==ID_main) add_argc_argv(symbol); // check the labels for(std::map<irep_idt, source_locationt>::const_iterator it=labels_used.begin(); it!=labels_used.end(); it++) { if(labels_defined.find(it->first)==labels_defined.end()) { err_location(it->second); str << "branching label `" << it->first << "' is not defined in function"; throw 0; } } }
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 jsil_typecheckt::typecheck_block(codet &code) { Forall_operands(it, code) typecheck_code(to_code(*it)); }
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); }