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 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); }
void c_typecheck_baset::typecheck_declaration( ansi_c_declarationt &declaration) { if(declaration.get_is_static_assert()) { assert(declaration.operands().size()==2); typecheck_expr(declaration.op0()); typecheck_expr(declaration.op1()); } else { // get storage spec c_storage_spect c_storage_spec(declaration.type()); // first typecheck the type of the declaration typecheck_type(declaration.type()); // mark as 'already typechecked' make_already_typechecked(declaration.type()); codet contract; { exprt spec_requires= static_cast<const exprt&>(declaration.find(ID_C_spec_requires)); contract.add(ID_C_spec_requires).swap(spec_requires); exprt spec_ensures= static_cast<const exprt&>(declaration.find(ID_C_spec_ensures)); contract.add(ID_C_spec_ensures).swap(spec_ensures); } // Now do declarators, if any. for(ansi_c_declarationt::declaratorst::iterator d_it=declaration.declarators().begin(); d_it!=declaration.declarators().end(); d_it++) { c_storage_spect full_spec(declaration.full_type(*d_it)); full_spec|=c_storage_spec; declaration.set_is_inline(full_spec.is_inline); declaration.set_is_static(full_spec.is_static); declaration.set_is_extern(full_spec.is_extern); declaration.set_is_thread_local(full_spec.is_thread_local); declaration.set_is_register(full_spec.is_register); declaration.set_is_typedef(full_spec.is_typedef); declaration.set_is_weak(full_spec.is_weak); symbolt symbol; declaration.to_symbol(*d_it, symbol); current_symbol=symbol; // now check other half of type typecheck_type(symbol.type); if(!full_spec.alias.empty()) { if(symbol.value.is_not_nil()) { error().source_location=symbol.location; error() << "alias attribute cannot be used with a body" << eom; throw 0; } // alias function need not have been declared yet, thus // can't lookup symbol.value=symbol_exprt(full_spec.alias); symbol.is_macro=true; } if(full_spec.section.empty()) apply_asm_label(full_spec.asm_label, symbol); else { std::string asm_name; asm_name=id2string(full_spec.section)+"$$"; if(!full_spec.asm_label.empty()) asm_name+=id2string(full_spec.asm_label); else asm_name+=id2string(symbol.name); apply_asm_label(asm_name, symbol); } irep_idt identifier=symbol.name; d_it->set_name(identifier); typecheck_symbol(symbol); // add code contract (if any); we typecheck this after the // function body done above, so as to have parameter symbols // available symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); assert(s_it!=symbol_table.symbols.end()); symbolt &new_symbol=s_it->second; typecheck_spec_expr(contract, ID_C_spec_requires); typet ret_type=empty_typet(); if(new_symbol.type.id()==ID_code) ret_type=to_code_type(new_symbol.type).return_type(); assert(parameter_map.empty()); if(ret_type.id()!=ID_empty) parameter_map["__CPROVER_return_value"]=ret_type; typecheck_spec_expr(contract, ID_C_spec_ensures); parameter_map.clear(); if(contract.find(ID_C_spec_requires).is_not_nil()) new_symbol.type.add(ID_C_spec_requires)= contract.find(ID_C_spec_requires); if(contract.find(ID_C_spec_ensures).is_not_nil()) new_symbol.type.add(ID_C_spec_ensures)= contract.find(ID_C_spec_ensures); } } }