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()); declaration.set_is_inline(c_storage_spec.is_inline); declaration.set_is_static(c_storage_spec.is_static); declaration.set_is_extern(c_storage_spec.is_extern); declaration.set_is_thread_local(c_storage_spec.is_thread_local); declaration.set_is_register(c_storage_spec.is_register); declaration.set_is_typedef(c_storage_spec.is_typedef); // first typecheck the type of the declaration typecheck_type(declaration.type()); // mark as 'already typechecked' make_already_typechecked(declaration.type()); // Now do declarators, if any. for(ansi_c_declarationt::declaratorst::iterator d_it=declaration.declarators().begin(); d_it!=declaration.declarators().end(); d_it++) { symbolt symbol; declaration.to_symbol(*d_it, symbol); // now check other half of type typecheck_type(symbol.type); typecheck_symbol(symbol); } } }
void c_typecheck_baset::typecheck_compound_body( struct_union_typet &type) { struct_union_typet::componentst &components=type.components(); struct_union_typet::componentst old_components; old_components.swap(components); // We get these as declarations! for(auto &decl : old_components) { // the arguments are member declarations or static assertions assert(decl.id()==ID_declaration); ansi_c_declarationt &declaration= to_ansi_c_declaration(static_cast<exprt &>(decl)); if(declaration.get_is_static_assert()) { struct_union_typet::componentt new_component; new_component.id(ID_static_assert); new_component.add_source_location()=declaration.source_location(); new_component.operands().swap(declaration.operands()); assert(new_component.operands().size()==2); components.push_back(new_component); } else { // do first half of type typecheck_type(declaration.type()); make_already_typechecked(declaration.type()); for(const auto &declarator : declaration.declarators()) { struct_union_typet::componentt new_component; new_component.add_source_location()= declarator.source_location(); new_component.set(ID_name, declarator.get_base_name()); new_component.set(ID_pretty_name, declarator.get_base_name()); new_component.type()=declaration.full_type(declarator); typecheck_type(new_component.type()); if(!is_complete_type(new_component.type()) && (new_component.type().id()!=ID_array || !to_array_type(new_component.type()).is_incomplete())) { error().source_location=new_component.type().source_location(); error() << "incomplete type not permitted here" << eom; throw 0; } components.push_back(new_component); } } } unsigned anon_member_counter=0; // scan for anonymous members, and name them for(auto &member : components) { if(member.get_name()!=irep_idt()) continue; member.set_name("$anon"+std::to_string(anon_member_counter++)); member.set_anonymous(true); } // scan for duplicate members { std::unordered_set<irep_idt, irep_id_hash> members; for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(!members.insert(it->get_name()).second) { error().source_location=it->source_location(); error() << "duplicate member '" << it->get_name() << '\'' << eom; throw 0; } } } // We allow an incomplete (C99) array as _last_ member! // Zero-length is allowed everywhere. if(type.id()==ID_struct || type.id()==ID_union) { for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { typet &c_type=it->type(); if(c_type.id()==ID_array && to_array_type(c_type).is_incomplete()) { // needs to be last member if(type.id()==ID_struct && it!=--components.end()) { error().source_location=it->source_location(); error() << "flexible struct member must be last member" << eom; throw 0; } // make it zero-length c_type.id(ID_array); c_type.set(ID_size, from_integer(0, index_type())); } } } // We may add some minimal padding inside and at // the end of structs and // as additional member for unions. if(type.id()==ID_struct) add_padding(to_struct_type(type), *this); else if(type.id()==ID_union) add_padding(to_union_type(type), *this); // Now remove zero-width bit-fields, these are just // for adjusting alignment. for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // blank { if(it->type().id()==ID_c_bit_field && to_c_bit_field_type(it->type()).get_width()==0) it=components.erase(it); else it++; } // finally, check _Static_assert inside the compound for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // no it++ { if(it->id()==ID_static_assert) { assert(it->operands().size()==2); exprt &assertion=it->op0(); typecheck_expr(assertion); typecheck_expr(it->op1()); assertion.make_typecast(bool_typet()); make_constant(assertion); if(assertion.is_false()) { error().source_location=it->source_location(); error() << "failed _Static_assert" << eom; throw 0; } else if(!assertion.is_true()) { // should warn/complain } it=components.erase(it); } else it++; } }
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); } } }