void c_typecheck_baset::do_initializer(symbolt &symbol) { // this one doesn't need initialization if(has_prefix(id2string(symbol.name), CPROVER_PREFIX "constant_infinity")) return; if(symbol.static_lifetime) { if(symbol.value.is_nil()) { const typet &final_type=follow(symbol.type); if(final_type.id()!=ID_incomplete_struct && final_type.id()!=ID_incomplete_array && final_type.id()!=ID_empty) { // zero initializer symbol.value=zero_initializer(symbol.type, symbol.location); symbol.value.set("#zero_initializer", true); } } else { typecheck_expr(symbol.value); do_initializer(symbol.value, symbol.type, true); if(follow(symbol.type).id()==ID_incomplete_array) symbol.type=symbol.value.type(); } } else if(!symbol.is_type) { const typet &final_type=follow(symbol.type); if(final_type.id()==ID_incomplete_c_enum || final_type.id()==ID_c_enum) { if(symbol.is_macro) { // these must have a constant value assert(symbol.value.is_not_nil()); typecheck_expr(symbol.value); locationt location=symbol.value.location(); do_initializer(symbol.value, symbol.type, true); make_constant(symbol.value); } } else if(symbol.value.is_not_nil()) { typecheck_expr(symbol.value); do_initializer(symbol.value, symbol.type, true); if(follow(symbol.type).id()==ID_incomplete_array) symbol.type=symbol.value.type(); } } }
void c_typecheck_baset::typecheck_new_symbol(symbolt &symbol) { if(symbol.is_parameter) adjust_function_parameter(symbol.type); // check initializer, if needed if(symbol.type.id()==ID_code) { if(symbol.value.is_not_nil() && !symbol.is_macro) typecheck_function_body(symbol); else { // we don't need the identifiers code_typet &code_type=to_code_type(symbol.type); for(code_typet::parameterst::iterator it=code_type.parameters().begin(); it!=code_type.parameters().end(); it++) it->set_identifier(irep_idt()); } } else { // check the initializer do_initializer(symbol); } }
void c_typecheck_baset::do_initializer(symbolt &symbol) { // this one doesn't need initialization if(has_prefix(id2string(symbol.name), CPROVER_PREFIX "constant_infinity")) return; if(symbol.is_static_lifetime) { if(symbol.value.is_not_nil()) { typecheck_expr(symbol.value); do_initializer(symbol.value, symbol.type, true); // need to adjust size? if(follow(symbol.type).id()==ID_array && to_array_type(follow(symbol.type)).size().is_nil()) symbol.type=symbol.value.type(); } } else if(!symbol.is_type) { if(symbol.is_macro) { // these must have a constant value assert(symbol.value.is_not_nil()); typecheck_expr(symbol.value); source_locationt location=symbol.value.source_location(); do_initializer(symbol.value, symbol.type, true); make_constant(symbol.value); } else if(symbol.value.is_not_nil()) { typecheck_expr(symbol.value); do_initializer(symbol.value, symbol.type, true); // need to adjust size? if(follow(symbol.type).id()==ID_array && to_array_type(follow(symbol.type)).size().is_nil()) symbol.type=symbol.value.type(); } } }
void c_typecheck_baset::typecheck_new_symbol(symbolt &symbol) { if(symbol.is_parameter) adjust_function_parameter(symbol.type); // check initializer, if needed if(symbol.type.id()==ID_code) { if(symbol.value.is_not_nil()) typecheck_function_body(symbol); else { // we don't need the identifiers code_typet &code_type=to_code_type(symbol.type); for(code_typet::parameterst::iterator it=code_type.parameters().begin(); it!=code_type.parameters().end(); it++) it->set_identifier(irep_idt()); } } else { if(symbol.type.id()==ID_array && to_array_type(symbol.type).size().is_nil() && !symbol.is_type) { // Insert a new type symbol for the array. // We do this because we want a convenient way // of adjusting the size of the type later on. type_symbolt new_symbol(symbol.type); new_symbol.name=id2string(symbol.name)+"$type"; new_symbol.base_name=id2string(symbol.base_name)+"$type"; new_symbol.location=symbol.location; new_symbol.mode=symbol.mode; new_symbol.module=symbol.module; symbol.type=symbol_typet(new_symbol.name); symbolt *new_sp; symbol_table.move(new_symbol, new_sp); } // check the initializer do_initializer(symbol); } }
void c_typecheck_baset::typecheck_redefinition_non_type( symbolt &old_symbol, symbolt &new_symbol) { const typet &final_old=follow(old_symbol.type); const typet &initial_new=follow(new_symbol.type); if(final_old.id()==ID_array && to_array_type(final_old).size().is_not_nil() && initial_new.id()==ID_array && to_array_type(initial_new).size().is_nil() && final_old.subtype()==initial_new.subtype()) { // this is ok, just use old type new_symbol.type=old_symbol.type; } // do initializer, this may change the type if(follow(new_symbol.type).id()!=ID_code) do_initializer(new_symbol); const typet &final_new=follow(new_symbol.type); // K&R stuff? if(old_symbol.type.id()==ID_KnR) { // check the type if(final_new.id()==ID_code) { err_location(new_symbol.location); throw "function type not allowed for K&R function parameter"; } // fix up old symbol -- we now got the type old_symbol.type=new_symbol.type; return; } if(final_new.id()==ID_code) { bool inlined= (new_symbol.type.get_bool(ID_C_inlined) || old_symbol.type.get_bool(ID_C_inlined)); if(final_old.id()!=ID_code) { err_location(new_symbol.location); str << "error: function symbol `" << new_symbol.display_name() << "' redefined with a different type:" << "\n"; str << "Original: " << to_string(old_symbol.type) << "\n"; str << " New: " << to_string(new_symbol.type); throw 0; } code_typet &old_ct=to_code_type(old_symbol.type); code_typet &new_ct=to_code_type(new_symbol.type); if(old_ct.has_ellipsis() && !new_ct.has_ellipsis()) old_ct=new_ct; else if(!old_ct.has_ellipsis() && new_ct.has_ellipsis()) new_ct=old_ct; if(inlined) { old_symbol.type.set(ID_C_inlined, true); new_symbol.type.set(ID_C_inlined, true); } // do body if(new_symbol.value.is_not_nil()) { if(old_symbol.value.is_not_nil()) { // gcc allows re-definition if the first // definition is marked as "extern inline" if(old_symbol.type.get_bool(ID_C_inlined) && (config.ansi_c.mode==configt::ansi_ct::flavourt::MODE_GCC_C || config.ansi_c.mode==configt::ansi_ct::flavourt::MODE_ARM_C_CPP)) { // overwrite "extern inline" properties old_symbol.is_extern=new_symbol.is_extern; old_symbol.is_file_local=new_symbol.is_file_local; // remove parameter declarations to avoid conflicts const code_typet::parameterst &old_p=old_ct.parameters(); for(code_typet::parameterst::const_iterator p_it=old_p.begin(); p_it!=old_p.end(); p_it++) { const irep_idt &identifier=p_it->get_identifier(); symbol_tablet::symbolst::iterator p_s_it= symbol_table.symbols.find(identifier); if(p_s_it!=symbol_table.symbols.end()) symbol_table.symbols.erase(p_s_it); } } else { err_location(new_symbol.location); str << "function body `" << new_symbol.display_name() << "' defined twice"; error_msg(); throw 0; } } else if(inlined) { // preserve "extern inline" properties old_symbol.is_extern=new_symbol.is_extern; old_symbol.is_file_local=new_symbol.is_file_local; } typecheck_function_body(new_symbol); // overwrite location old_symbol.location=new_symbol.location; // move body old_symbol.value.swap(new_symbol.value); // overwrite type (because of parameter names) old_symbol.type=new_symbol.type; } return; } if(final_old!=final_new) { if(final_old.id()==ID_array && to_array_type(final_old).size().is_nil() && final_new.id()==ID_array && to_array_type(final_new).size().is_not_nil() && final_old.subtype()==final_new.subtype()) { // this is also ok if(old_symbol.type.id()==ID_symbol) { // fix the symbol, not just the type const irep_idt identifier= to_symbol_type(old_symbol.type).get_identifier(); symbol_tablet::symbolst::iterator s_it=symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) { err_location(old_symbol.location); str << "typecheck_redefinition_non_type: " "failed to find symbol `" << identifier << "'"; throw 0; } symbolt &symbol=s_it->second; symbol.type=final_new; } else old_symbol.type=new_symbol.type; } else if((final_old.id()==ID_incomplete_c_enum || final_old.id()==ID_c_enum) && (final_new.id()==ID_incomplete_c_enum || final_new.id()==ID_c_enum)) { // this is ok for now } else if(final_old.id()==ID_pointer && follow(final_old).subtype().id()==ID_code && to_code_type(follow(final_old).subtype()).has_ellipsis() && final_new.id()==ID_pointer && follow(final_new).subtype().id()==ID_code) { // to allow // int (*f) (); // int (*f) (int)=0; old_symbol.type=new_symbol.type; } else if(final_old.id()==ID_pointer && follow(final_old).subtype().id()==ID_code && final_new.id()==ID_pointer && follow(final_new).subtype().id()==ID_code && to_code_type(follow(final_new).subtype()).has_ellipsis()) { // to allow // int (*f) (int)=0; // int (*f) (); } else { err_location(new_symbol.location); str << "error: symbol `" << new_symbol.display_name() << "' redefined with a different type:" << "\n"; str << "Original: " << to_string(old_symbol.type) << "\n"; str << " New: " << to_string(new_symbol.type); throw 0; } } else // finals are equal { } // do value if(new_symbol.value.is_not_nil()) { // see if we already have one if(old_symbol.value.is_not_nil()) { if(new_symbol.value.get_bool(ID_C_zero_initializer)) { // do nothing } else if(old_symbol.value.get_bool(ID_C_zero_initializer)) { old_symbol.value=new_symbol.value; old_symbol.type=new_symbol.type; } else { if(new_symbol.is_macro && (final_new.id()==ID_incomplete_c_enum || final_new.id()==ID_c_enum) && old_symbol.value.is_constant() && new_symbol.value.is_constant() && old_symbol.value.get(ID_value)==new_symbol.value.get(ID_value)) { // ignore } else { err_location(new_symbol.value); str << "symbol `" << new_symbol.display_name() << "' already has an initial value"; warning_msg(); } } } else { old_symbol.value=new_symbol.value; old_symbol.type=new_symbol.type; } } // take care of some flags if(old_symbol.is_extern && !new_symbol.is_extern) old_symbol.location=new_symbol.location; old_symbol.is_extern=old_symbol.is_extern && new_symbol.is_extern; // We should likely check is_volatile and // is_thread_local for consistency. GCC complains if these // mismatch. }