exprt c_typecheck_baset::do_initializer_rec( const exprt &value, const typet &type, bool force_constant) { const typet &full_type=follow(type); if(full_type.id()==ID_incomplete_struct) { err_location(value); error() << "type `" << to_string(full_type) << "' is still incomplete -- cannot initialize" << eom; throw 0; } if(value.id()==ID_initializer_list) return do_initializer_list(value, type, force_constant); if(value.id()==ID_array && value.get_bool(ID_C_string_constant) && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==value.type().subtype().get(ID_width)) { exprt tmp=value; // adjust char type tmp.type().subtype()=full_type.subtype(); Forall_operands(it, tmp) it->type()=full_type.subtype(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp.operands().resize(integer2size_t(array_size)); tmp.type()=type; } else if(mp_integer(tmp.operands().size())<array_size) { // fill up tmp.type()=type; exprt zero=zero_initializer(full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp.operands().resize(integer2size_t(array_size), zero); } } return tmp; } if(value.id()==ID_string_constant && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { // will go away, to be replaced by the above block string_constantt tmp1=to_string_constant(value); // adjust char type tmp1.type().subtype()=full_type.subtype(); exprt tmp2=tmp1.to_array_expr(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp2.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp2.operands().resize(integer2size_t(array_size)); tmp2.type()=type; } else if(mp_integer(tmp2.operands().size())<array_size) { // fill up tmp2.type()=type; exprt zero=zero_initializer(full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp2.operands().resize(integer2size_t(array_size), zero); } } return tmp2; } if(full_type.id()==ID_array && to_array_type(full_type).size().is_nil()) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with `" << to_string(value) << "'" << eom; throw 0; } if(value.id()==ID_designated_initializer) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with designated initializer" << eom; throw 0; } exprt result=value; implicit_typecast(result, type); return result; }
exprt c_typecheck_baset::do_initializer_list( const exprt &value, const typet &type, bool force_constant) { assert(value.id()==ID_initializer_list); const typet &full_type=follow(type); exprt result; if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { // start with zero everywhere result=zero_initializer(type, value.source_location(), *this, get_message_handler()); } else if(full_type.id()==ID_array) { if(to_array_type(full_type).size().is_nil()) { // start with empty array result=exprt(ID_array, full_type); result.add_source_location()=value.source_location(); } else { // start with zero everywhere result=zero_initializer(type, value.source_location(), *this, get_message_handler()); } // 6.7.9, 14: An array of character type may be initialized by a character // string literal or UTF-8 string literal, optionally enclosed in braces. if(value.operands().size()>=1 && value.op0().id()==ID_string_constant && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { if(value.operands().size()>1) { warning().source_location=value.find_source_location(); warning() << "ignoring excess initializers" << eom; } return do_initializer_rec(value.op0(), type, force_constant); } } else { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.operands().size()==1) return do_initializer_rec(value.op0(), type, force_constant); err_location(value); error() << "cannot initialize `" << to_string(full_type) << "' with an initializer list" << eom; throw 0; } designatort current_designator; designator_enter(type, current_designator); forall_operands(it, value) { do_designated_initializer( result, current_designator, *it, force_constant); // increase designator -- might go up increment_designator(current_designator); }
void c_typecheck_baset::do_designated_initializer( exprt &result, designatort &designator, const exprt &value, bool force_constant) { assert(!designator.empty()); if(value.id()==ID_designated_initializer) { assert(value.operands().size()==1); designator= make_designator( designator.front().type, static_cast<const exprt &>(value.find(ID_designator))); assert(!designator.empty()); return do_designated_initializer( result, designator, value.op0(), force_constant); } exprt *dest=&result; // first phase: follow given designator for(size_t i=0; i<designator.size(); i++) { size_t index=designator[i].index; const typet &type=designator[i].type; const typet &full_type=follow(type); if(full_type.id()==ID_array || full_type.id()==ID_vector) { if(index>=dest->operands().size()) { if(full_type.id()==ID_array && (to_array_type(full_type).size().is_zero() || to_array_type(full_type).size().is_nil())) { // we are willing to grow an incomplete or zero-sized array exprt zero=zero_initializer(full_type.subtype(), value.source_location(), *this, get_message_handler()); dest->operands().resize(integer2size_t(index)+1, zero); // todo: adjust type! } else { err_location(value); error() << "array index designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } } dest=&(dest->operands()[integer2size_t(index)]); } else if(full_type.id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(full_type).components(); if(index>=dest->operands().size()) { err_location(value); error() << "structure member designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } assert(index<components.size()); assert(components[index].type().id()!=ID_code && !components[index].get_is_padding()); dest=&(dest->operands()[index]); } else if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); assert(index<components.size()); const union_typet::componentt &component=union_type.components()[index]; if(dest->id()==ID_union && dest->get(ID_component_name)==component.get_name()) { // Already right union component. We can initialize multiple submembers, // so do not overwrite this. } else { // Note that gcc issues a warning if the union component is switched. // Build a union expression from given component. union_exprt union_expr(type); union_expr.op()=zero_initializer(component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } dest=&(dest->op0()); } else assert(false); } // second phase: assign value // for this, we may need to go down, adding to the designator while(true) { // see what type we have to initialize const typet &type=designator.back().subtype; const typet &full_type=follow(type); assert(full_type.id()!=ID_symbol); // do we initialize a scalar? if(full_type.id()!=ID_struct && full_type.id()!=ID_union && full_type.id()!=ID_array && full_type.id()!=ID_vector) { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.id()==ID_initializer_list && value.operands().size()==1) *dest=do_initializer_rec(value.op0(), type, force_constant); else *dest=do_initializer_rec(value, type, force_constant); assert(full_type==follow(dest->type())); return; // done } // union? The component in the zero initializer might // not be the first one. if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); if(!components.empty()) { const union_typet::componentt &component=union_type.components().front(); union_exprt union_expr(type); union_expr.op()=zero_initializer(component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } } // see what initializer we are given if(value.id()==ID_initializer_list) { *dest=do_initializer_rec(value, type, force_constant); return; // done } else if(value.id()==ID_string_constant) { // We stop for initializers that are string-constants, // which are like arrays. We only do so if we are to // initialize an array of scalars. if(full_type.id()==ID_array && (follow(full_type.subtype()).id()==ID_signedbv || follow(full_type.subtype()).id()==ID_unsignedbv)) { *dest=do_initializer_rec(value, type, force_constant); return; // done } } else if(follow(value.type())==full_type) { // a struct/union/vector can be initialized directly with // an expression of the right type. This doesn't // work with arrays, unfortunately. if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { *dest=value; return; // done } } assert(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_array || full_type.id()==ID_vector); // we are initializing a compound type, and enter it! // this may change the type, full_type might not be valid anymore const typet dest_type=full_type; designator_enter(type, designator); if(dest->operands().empty()) { err_location(value); error() << "cannot initialize type `" << to_string(dest_type) << "' using value `" << to_string(value) << "'" << eom; throw 0; } dest=&(dest->op0()); // we run into another loop iteration } }
designatort c_typecheck_baset::make_designator( const typet &src_type, const exprt &src) { assert(!src.operands().empty()); typet type=src_type; designatort designator; forall_operands(it, src) { const exprt &d_op=*it; designatort::entryt entry; entry.type=type; const typet &full_type=follow(entry.type); if(full_type.id()==ID_array) { if(d_op.id()!=ID_index) { err_location(d_op); error() << "expected array index designator" << eom; throw 0; } assert(d_op.operands().size()==1); exprt tmp_index=d_op.op0(); make_constant_index(tmp_index); mp_integer index, size; if(to_integer(tmp_index, index)) { err_location(d_op.op0()); error() << "expected constant array index designator" << eom; throw 0; } if(to_array_type(full_type).size().is_nil()) size=0; else if(to_integer(to_array_type(full_type).size(), size)) { err_location(d_op.op0()); error() << "expected constant array size" << eom; throw 0; } entry.index=integer2size_t(index); entry.size=integer2size_t(size); entry.subtype=full_type.subtype(); } else if(full_type.id()==ID_struct || full_type.id()==ID_union) { const struct_union_typet &struct_union_type=to_struct_union_type(full_type); if(d_op.id()!=ID_member) { err_location(d_op); error() << "expected member designator" << eom; throw 0; } const irep_idt &component_name=d_op.get(ID_component_name); if(struct_union_type.has_component(component_name)) { // a direct member entry.index=struct_union_type.component_number(component_name); entry.size=struct_union_type.components().size(); entry.subtype=struct_union_type.components()[entry.index].type(); } else { // We will search for anonymous members, // in a loop. This isn't supported by gcc, but icc does allow it. bool found=false, repeat; typet tmp_type=entry.type; do { repeat=false; unsigned number=0; const struct_union_typet::componentst &components= to_struct_union_type(follow(tmp_type)).components(); for(struct_union_typet::componentst::const_iterator c_it=components.begin(); c_it!=components.end(); c_it++, number++) { if(c_it->get_name()==component_name) { // done! entry.index=number; entry.size=components.size(); entry.subtype=components[entry.index].type(); entry.type=tmp_type; } else if(c_it->get_anonymous() && (follow(c_it->type()).id()==ID_struct || follow(c_it->type()).id()==ID_union) && has_component_rec( c_it->type(), component_name, *this)) { entry.index=number; entry.size=components.size(); entry.subtype=c_it->type(); entry.type=tmp_type; tmp_type=entry.subtype; designator.push_entry(entry); found=repeat=true; break; } } } while(repeat); if(!found) { err_location(d_op); error() << "failed to find struct component `" << component_name << "' in initialization of `" << to_string(struct_union_type) << "'" << eom; throw 0; } } } else { err_location(d_op); error() << "designated initializers cannot initialize `" << to_string(full_type) << "'" << eom; throw 0; } type=entry.subtype; designator.push_entry(entry); } assert(!designator.empty()); return designator; }
void linkingt::duplicate_non_type_symbol( symbolt &old_symbol, symbolt &new_symbol) { // We first take care of file-local non-type symbols. // These are static functions, or static variables // inside function bodies. if(new_symbol.is_file_local || old_symbol.is_file_local) { // we just always rename these irep_idt old_identifier=new_symbol.name; irep_idt new_identifier=rename(old_identifier); replace_symbol.insert( old_identifier, symbol_exprt(new_identifier, new_symbol.type)); new_symbol.name=new_identifier; // move over! bool result=main_symbol_table.move(new_symbol); assert(!result); return; } // see if it is a function or a variable bool is_code_old_symbol=old_symbol.type.id()==ID_code; bool is_code_new_symbol=new_symbol.type.id()==ID_code; if(is_code_old_symbol!=is_code_new_symbol) { err_location(new_symbol.location); str << "error: conflicting definition for symbol \"" << old_symbol.display_name() << "\"" << std::endl; str << "old definition in module " << old_symbol.module << " " << old_symbol.location << std::endl << to_string(old_symbol.type) << std::endl; str << "new definition in module " << new_symbol.module << " " << new_symbol.location << std::endl << to_string(new_symbol.type); throw 0; } if(is_code_old_symbol) { // Both are functions. // We don't compare the types, they will be too different; // we just care about the code if(!new_symbol.value.is_nil()) { if(old_symbol.value.is_nil()) { // the one with body wins! old_symbol.value=new_symbol.value; old_symbol.type=new_symbol.type; // for argument identifiers } else if(to_code_type(old_symbol.type).get_inlined()) { // ok, silently ignore } else if(base_type_eq(old_symbol.type, new_symbol.type, ns)) { // keep the one in old_symbol -- libraries come last! str << "warning: function `" << old_symbol.name << "' in module `" << new_symbol.module << "' is shadowed by a definition in module `" << old_symbol.module << "'"; warning(); } else { err_location(new_symbol.value); str << "error: duplicate definition of function `" << old_symbol.name << "'" << std::endl; str << "In module `" << old_symbol.module << "' and module `" << new_symbol.module << "'"; throw 0; } } } else { // both are variables if(!base_type_eq(old_symbol.type, new_symbol.type, ns)) { const typet &old_type=ns.follow(old_symbol.type); const typet &new_type=ns.follow(new_symbol.type); if(old_type.id()==ID_array && new_type.id()==ID_array && base_type_eq(old_type.subtype(), new_type.subtype(), ns)) { // still need to compare size const exprt &old_size=to_array_type(old_type).size(); const exprt &new_size=to_array_type(new_type).size(); if(old_size.is_nil() && new_size.is_not_nil()) { old_symbol.type=new_symbol.type; // store new type } else if(old_size.is_not_nil() && new_size.is_nil()) { // ok, we will use the old type } else { // size seems different, ignore for now } } else if(old_type.id()==ID_pointer && new_type.id()==ID_array) { // store new type old_symbol.type=new_symbol.type; } else if(old_type.id()==ID_array && new_type.id()==ID_pointer) { // ignore } else if(old_type.id()==ID_pointer && new_type.id()==ID_pointer) { // ignore, generally ok } else if(old_type.id()==ID_incomplete_struct && new_type.id()==ID_struct) { // store new type old_symbol.type=new_symbol.type; } else if(old_type.id()==ID_struct && new_type.id()==ID_incomplete_struct) { // ignore } else { err_location(new_symbol.location); str << "error: conflicting types for variable `" << old_symbol.name << "'" << std::endl; str << "old definition in module " << old_symbol.module << " " << old_symbol.location << std::endl << to_string_verbose(old_symbol.type) << std::endl; str << "new definition in module " << new_symbol.module << " " << new_symbol.location << std::endl << to_string_verbose(new_symbol.type); throw 0; } } // care about initializers if(!new_symbol.value.is_nil() && !new_symbol.value.get_bool(ID_C_zero_initializer)) { if(old_symbol.value.is_nil() || old_symbol.value.get_bool(ID_C_zero_initializer)) { // new_symbol wins old_symbol.value=new_symbol.value; } else { // try simplifier exprt tmp_old=old_symbol.value, tmp_new=new_symbol.value; simplify(tmp_old, ns); simplify(tmp_new, ns); if(base_type_eq(tmp_old, tmp_new, ns)) { // ok, the same } else { err_location(new_symbol.value); str << "error: conflicting initializers for variable `" << old_symbol.name << "'" << std::endl; str << "old value in module " << old_symbol.module << " " << old_symbol.value.find_location() << std::endl << to_string(tmp_old) << std::endl; str << "new value in module " << new_symbol.module << " " << new_symbol.value.find_location() << std::endl << to_string(tmp_new); throw 0; } } } // care about flags // it's enough that one isn't extern for the final one not to be old_symbol.is_extern=old_symbol.is_extern && new_symbol.is_extern; } }
void c_typecheck_baset::designator_enter( const typet &type, designatort &designator) { designatort::entryt entry; entry.type=type; entry.index=0; const typet &full_type=follow(type); if(full_type.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(full_type); entry.size=struct_type.components().size(); entry.subtype.make_nil(); for(struct_typet::componentst::const_iterator it=struct_type.components().begin(); it!=struct_type.components().end(); ++it) { if(it->type().id()!=ID_code && !it->get_is_padding()) { entry.subtype=it->type(); break; } ++entry.index; } } else if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); if(union_type.components().empty()) { entry.size=0; entry.subtype.make_nil(); } else { // The default is to unitialize using the first member of the // union. entry.size=1; entry.subtype=union_type.components().front().type(); } } else if(full_type.id()==ID_array) { const array_typet &array_type=to_array_type(full_type); if(array_type.size().is_nil()) { entry.size=0; entry.subtype=array_type.subtype(); } else { mp_integer array_size; if(to_integer(array_type.size(), array_size)) { err_location(array_type.size()); error() << "array has non-constant size `" << to_string(array_type.size()) << "'" << eom; throw 0; } entry.size=integer2size_t(array_size); entry.subtype=array_type.subtype(); } } else if(full_type.id()==ID_vector) { const vector_typet &vector_type=to_vector_type(full_type); mp_integer vector_size; if(to_integer(vector_type.size(), vector_size)) { err_location(vector_type.size()); error() << "vector has non-constant size `" << to_string(vector_type.size()) << "'" << eom; throw 0; } entry.size=integer2size_t(vector_size); entry.subtype=vector_type.subtype(); } else assert(false); designator.push_entry(entry); }
void cpp_typecheckt::typecheck_compound_type( struct_union_typet &type) { // first save qualifiers c_qualifierst qualifiers(type); // now clear them from the type type.remove(ID_C_constant); type.remove(ID_C_volatile); type.remove(ID_C_restricted); // get the tag name bool anonymous=type.find(ID_tag).is_nil(); irep_idt base_name; cpp_scopet *dest_scope=NULL; bool has_body=type.find(ID_body).is_not_nil(); bool tag_only_declaration=type.get_bool(ID_C_tag_only_declaration); if(anonymous) { base_name="#anon_"+type.id_string()+i2string(anon_counter++); type.set("#is_anonymous", true); // anonymous structs always go into the current scope dest_scope=&cpp_scopes.current_scope(); } else { const cpp_namet &cpp_name= to_cpp_name(type.find(ID_tag)); // scope given? if(cpp_name.is_simple_name()) { base_name=cpp_name.get_base_name(); dest_scope=&tag_scope(base_name, has_body, tag_only_declaration); } else { cpp_save_scopet cpp_save_scope(cpp_scopes); cpp_typecheck_resolvet cpp_typecheck_resolve(*this); cpp_template_args_non_tct t_args; dest_scope=&cpp_typecheck_resolve.resolve_scope(cpp_name, base_name, t_args); } } const irep_idt symbol_name= language_prefix+ dest_scope->prefix+ "tag."+id2string(base_name); // check if we have it already contextt::symbolst::iterator previous_symbol= context.symbols.find(symbol_name); if(previous_symbol!=context.symbols.end()) { // we do! symbolt &symbol=previous_symbol->second; if(has_body) { if(symbol.type.id()=="incomplete_"+type.id_string()) { // a previously incomplete struct/union becomes complete symbol.type.swap(type); typecheck_compound_body(symbol); } else { err_location(type.location()); str << "error: struct symbol `" << base_name << "' declared previously" << std::endl; str << "location of previous definition: " << symbol.location; throw 0; } } } else { // produce new symbol symbolt symbol; symbol.name=symbol_name; symbol.base_name=base_name; symbol.value.make_nil(); symbol.location=type.location(); symbol.mode=ID_cpp; symbol.module=module; symbol.type.swap(type); symbol.is_type=true; symbol.is_macro=false; symbol.pretty_name=cpp_scopes.current_scope().prefix+id2string(symbol.base_name); symbol.type.set(ID_tag, symbol.pretty_name); // move early, must be visible before doing body symbolt *new_symbol; if(context.move(symbol, new_symbol)) throw "cpp_typecheckt::typecheck_compound_type: context.move() failed"; // put into dest_scope cpp_idt &id=cpp_scopes.put_into_scope(*new_symbol, *dest_scope); id.id_class=cpp_idt::CLASS; id.is_scope=true; id.prefix=cpp_scopes.current_scope().prefix+ id2string(new_symbol->base_name)+"::"; id.class_identifier=new_symbol->name; id.id_class=cpp_idt::CLASS; if(has_body) typecheck_compound_body(*new_symbol); else { typet new_type("incomplete_"+new_symbol->type.id_string()); new_type.set(ID_tag, new_symbol->base_name); new_symbol->type.swap(new_type); } } // create type symbol typet symbol_type(ID_symbol); symbol_type.set(ID_identifier, symbol_name); qualifiers.write(symbol_type); type.swap(symbol_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 cpp_typecheckt::put_compound_into_scope( const struct_union_typet::componentt &compound) { const irep_idt &base_name=compound.get_base_name(); const irep_idt &name=compound.get_name(); // nothing to do if no base_name (e.g., an anonymous bitfield) if(base_name==irep_idt()) return; if(compound.type().id()==ID_code) { // put the symbol into scope cpp_idt &id=cpp_scopes.current_scope().insert(base_name); id.id_class=compound.get_bool("is_type")?cpp_idt::TYPEDEF:cpp_idt::SYMBOL; id.identifier=name; id.class_identifier=cpp_scopes.current_scope().identifier; id.is_member = true; id.is_constructor = compound.find(ID_type).get(ID_return_type) == ID_constructor; id.is_method = true; id.is_static_member=compound.get_bool(ID_is_static); // create function block-scope in the scope cpp_idt &id_block= cpp_scopes.current_scope().insert( irep_idt(std::string("$block:") + base_name.c_str())); id_block.id_class=cpp_idt::BLOCK_SCOPE; id_block.identifier=name; id_block.class_identifier=cpp_scopes.current_scope().identifier; id_block.is_method=true; id_block.is_static_member=compound.get_bool(ID_is_static); id_block.is_scope=true; id_block.prefix=compound.get_string("prefix"); cpp_scopes.id_map[id.identifier]=&id_block; } else { // check if it's already there cpp_scopest::id_sett id_set; cpp_scopes.current_scope().lookup(base_name, cpp_scopet::SCOPE_ONLY, id_set); for(cpp_scopest::id_sett::const_iterator id_it=id_set.begin(); id_it!=id_set.end(); id_it++) { const cpp_idt &id=**id_it; // the name is already in the scope // this is ok if they belong to different categories if(!id.is_class() && !id.is_enum()) { err_location(compound); str << "`" << base_name << "' already in compound scope"; throw 0; } } // put into the scope cpp_idt &id=cpp_scopes.current_scope().insert(base_name); id.id_class=compound.get_bool(ID_is_type)?cpp_idt::TYPEDEF:cpp_idt::SYMBOL; id.identifier=name; id.class_identifier=cpp_scopes.current_scope().identifier; id.is_member=true; id.is_method=false; id.is_static_member=compound.get_bool(ID_is_static); } }
void cpp_typecheckt::typecheck_friend_declaration( symbolt &symbol, cpp_declarationt &declaration) { // A friend of a class can be a function/method, // or a struct/class/union type. if(declaration.is_template()) { return; // TODO err_location(declaration.type().location()); str << "friend template not supported"; throw 0; } // we distinguish these whether there is a declarator if(declaration.declarators().empty()) { typet &ftype=declaration.type(); // must be struct or union if(ftype.id()!=ID_struct && ftype.id()!=ID_union) { err_location(declaration.type()); str << "unexpected friend"; throw 0; } if(ftype.find(ID_body).is_not_nil()) { err_location(declaration.type()); str << "friend declaration must not have compound body"; throw 0; } // typecheck ftype // TODO // typecheck_type(ftype); // assert(ftype.id()==ID_symbol); // symbol.type.add("#friends").move_to_sub(ftype); return; } // It should be a friend function. // Do the declarators. Forall_cpp_declarators(sub_it, declaration) { bool has_value = sub_it->value().is_not_nil(); if(!has_value) { // If no value is found, then we jump to the // global scope, and we convert the declarator // as if it were declared there cpp_save_scopet saved_scope(cpp_scopes); cpp_scopes.go_to_global_scope(); cpp_declarator_convertert cpp_declarator_converter(*this); const symbolt &conv_symb = cpp_declarator_converter.convert( declaration.type(), declaration.storage_spec(), declaration.member_spec(), *sub_it); exprt symb_expr = cpp_symbol_expr(conv_symb); symbol.type.add("#friends").move_to_sub(symb_expr); } else { cpp_declarator_convertert cpp_declarator_converter(*this); cpp_declarator_converter.is_friend = true; declaration.member_spec().set_inline(true); const symbolt &conv_symb = cpp_declarator_converter.convert( declaration.type(), declaration.storage_spec(), declaration.member_spec(), *sub_it); exprt symb_expr = cpp_symbol_expr(conv_symb); symbol.type.add("#friends").move_to_sub(symb_expr); } }
void cpp_typecheckt::typecheck_compound_declarator( const symbolt &symbol, const cpp_declarationt &declaration, cpp_declaratort &declarator, struct_typet::componentst &components, const irep_idt &access, bool is_static, bool is_typedef, bool is_mutable) { bool is_cast_operator= declaration.type().id()=="cpp-cast-operator"; if(is_cast_operator) { assert(declarator.name().get_sub().size()==2 && declarator.name().get_sub().front().id()==ID_operator); typet type=static_cast<typet &>(declarator.name().get_sub()[1]); declarator.type().subtype()=type; irept name(ID_name); name.set(ID_identifier, "("+cpp_type2name(type)+")"); declarator.name().get_sub().back().swap(name); } typet final_type= declarator.merge_type(declaration.type()); // this triggers template elaboration elaborate_class_template(final_type); typecheck_type(final_type); cpp_namet cpp_name; cpp_name.swap(declarator.name()); irep_idt base_name; if(cpp_name.is_nil()) { // Yes, there can be members without name. base_name=irep_idt(); } else if(cpp_name.is_simple_name()) { base_name=cpp_name.get_base_name(); } else { err_location(cpp_name.location()); str << "declarator in compound needs to be simple name"; throw 0; } bool is_method=!is_typedef && final_type.id()==ID_code; bool is_constructor=declaration.is_constructor(); bool is_destructor=declaration.is_destructor(); bool is_virtual=declaration.member_spec().is_virtual(); bool is_explicit=declaration.member_spec().is_explicit(); bool is_inline=declaration.member_spec().is_inline(); final_type.set(ID_C_member_name, symbol.name); // first do some sanity checks if(is_virtual && !is_method) { err_location(cpp_name.location()); str << "only methods can be virtual"; throw 0; } if(is_inline && !is_method) { err_location(cpp_name.location()); str << "only methods can be inlined"; throw 0; } if(is_virtual && is_static) { err_location(cpp_name.location()); str << "static methods cannot be virtual"; throw 0; } if(is_cast_operator && is_static) { err_location(cpp_name.location()); str << "cast operators cannot be static`"; throw 0; } if(is_constructor && is_virtual) { err_location(cpp_name.location()); str << "constructors cannot be virtual"; throw 0; } if(!is_constructor && is_explicit) { err_location(cpp_name.location()); str << "only constructors can be explicit"; throw 0; } if(is_constructor && base_name!=id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "member function must return a value or void"; throw 0; } if(is_destructor && base_name!="~"+id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "destructor with wrong name"; throw 0; } // now do actual work struct_typet::componentt component; irep_idt identifier= language_prefix+ cpp_scopes.current_scope().prefix+ id2string(base_name); component.set(ID_name, identifier); component.type()=final_type; component.set(ID_access, access); component.set(ID_base_name, base_name); component.set(ID_pretty_name, base_name); component.location()=cpp_name.location(); if(cpp_name.is_operator()) { component.set("is_operator", true); component.type().set("#is_operator", true); } if(is_cast_operator) component.set("is_cast_operator", true); if(declaration.member_spec().is_explicit()) component.set("is_explicit", true); typet &method_qualifier= (typet &)declarator.add("method_qualifier"); if(is_static) { component.set(ID_is_static, true); component.type().set("#is_static", true); } if(is_typedef) component.set("is_type", true); if(is_mutable) component.set("is_mutable", true); exprt &value=declarator.value(); irept &initializers=declarator.member_initializers(); if(is_method) { component.set(ID_is_inline, declaration.member_spec().is_inline()); // the 'virtual' name of the function std::string virtual_name= component.get_string(ID_base_name)+ id2string( function_identifier(static_cast<const typet &>(component.find(ID_type)))); if(method_qualifier.id()==ID_const) virtual_name += "$const"; if(component.type().get(ID_return_type) == ID_destructor) virtual_name= "@dtor"; // The method may be virtual implicitly. std::set<irep_idt> virtual_bases; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_bool("is_virtual")) { if(it->get("virtual_name")==virtual_name) { is_virtual=true; const code_typet& code_type = to_code_type(it->type()); assert(code_type.arguments().size()>0); const typet& pointer_type = code_type.arguments()[0].type(); assert(pointer_type.id() == ID_pointer); virtual_bases.insert(pointer_type.subtype().get(ID_identifier)); } } } if(!is_virtual) { typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); if(!value.is_nil() && !is_static) { err_location(cpp_name.location()); str << "no initialization allowed here"; throw 0; } } else // virtual { component.type().set("#is_virtual", true); component.type().set("#virtual_name",virtual_name); // Check if it is a pure virtual method if(is_virtual) { if(value.is_not_nil() && value.id() == ID_constant) { mp_integer i; to_integer(value, i); if(i!=0) { err_location(declarator.name().location()); str << "expected 0 to mark pure virtual method, got " << i; } component.set("is_pure_virtual", true); value.make_nil(); } } typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); // get the virtual-table symbol type irep_idt vt_name = "virtual_table::"+symbol.name.as_string(); contextt::symbolst::iterator vtit = context.symbols.find(vt_name); if(vtit == context.symbols.end()) { // first time: create a virtual-table symbol type symbolt vt_symb_type; vt_symb_type.name= vt_name; vt_symb_type.base_name="virtual_table::"+symbol.base_name.as_string(); vt_symb_type.pretty_name = vt_symb_type.base_name; vt_symb_type.mode=ID_cpp; vt_symb_type.module=module; vt_symb_type.location=symbol.location; vt_symb_type.type = struct_typet(); vt_symb_type.type.set(ID_name, vt_symb_type.name); vt_symb_type.is_type = true; bool failed = context.move(vt_symb_type); assert(!failed); vtit = context.symbols.find(vt_name); // add a virtual-table pointer struct_typet::componentt compo; compo.type() = pointer_typet(symbol_typet(vt_name)); compo.set_name(symbol.name.as_string() +"::@vtable_pointer"); compo.set(ID_base_name, "@vtable_pointer"); compo.set(ID_pretty_name, symbol.base_name.as_string() +"@vtable_pointer"); compo.set("is_vtptr", true); compo.set(ID_access, ID_public); components.push_back(compo); put_compound_into_scope(compo); } assert(vtit->second.type.id()==ID_struct); struct_typet &virtual_table= to_struct_type(vtit->second.type); component.set("virtual_name", virtual_name); component.set("is_virtual", is_virtual); // add an entry to the virtual table struct_typet::componentt vt_entry; vt_entry.type() = pointer_typet(component.type()); vt_entry.set_name(vtit->first.as_string()+"::"+virtual_name); vt_entry.set(ID_base_name, virtual_name); vt_entry.set(ID_pretty_name, virtual_name); vt_entry.set(ID_access, ID_public); vt_entry.location() = symbol.location; virtual_table.components().push_back(vt_entry); // take care of overloading while(!virtual_bases.empty()) { irep_idt virtual_base = *virtual_bases.begin(); // a new function that does 'late casting' of the 'this' parameter symbolt func_symb; func_symb.name=component.get_name().as_string() + "::" +virtual_base.as_string(); func_symb.base_name=component.get(ID_base_name); func_symb.pretty_name = component.get(ID_base_name); func_symb.mode=ID_cpp; func_symb.module=module; func_symb.location=component.location(); func_symb.type=component.type(); // change the type of the 'this' pointer code_typet& code_type = to_code_type(func_symb.type); code_typet::argumentt& arg= code_type.arguments().front(); arg.type().subtype().set(ID_identifier, virtual_base); // create symbols for the arguments code_typet::argumentst& args = code_type.arguments(); for(unsigned i=0; i<args.size(); i++) { code_typet::argumentt& arg = args[i]; irep_idt base_name = arg.get_base_name(); if(base_name==irep_idt()) base_name="arg"+i2string(i); symbolt arg_symb; arg_symb.name = func_symb.name.as_string() + "::"+ base_name.as_string(); arg_symb.base_name = base_name; arg_symb.pretty_name = base_name; arg_symb.mode=ID_cpp; arg_symb.location=func_symb.location; arg_symb.type = arg.type(); arg.set(ID_C_identifier, arg_symb.name); // add the argument to the symbol table bool failed = context.move(arg_symb); assert(!failed); } // do the body of the function typecast_exprt late_cast(to_code_type(component.type()).arguments()[0].type()); late_cast.op0()= symbol_expr(namespacet(context).lookup( args[0].get(ID_C_identifier))); if(code_type.return_type().id()!=ID_empty && code_type.return_type().id()!=ID_destructor) { side_effect_expr_function_callt expr_call; expr_call.function() = symbol_exprt(component.get_name(),component.type()); expr_call.type() = to_code_type(component.type()).return_type(); expr_call.arguments().reserve(args.size()); expr_call.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { expr_call.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } code_returnt code_return; code_return.return_value() = expr_call; func_symb.value = code_return; } else { code_function_callt code_func; code_func.function() = symbol_exprt(component.get_name(),component.type()); code_func.arguments().reserve(args.size()); code_func.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { code_func.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } func_symb.value = code_func; } // add this new function to the list of components struct_typet::componentt new_compo = component; new_compo.type() = func_symb.type; new_compo.set_name(func_symb.name); components.push_back(new_compo); // add the function to the symbol table { bool failed = context.move(func_symb); assert(!failed); } // next base virtual_bases.erase(virtual_bases.begin()); } } } if(is_static && !is_method) // static non-method member { // add as global variable to context symbolt static_symbol; static_symbol.mode=symbol.mode; static_symbol.name=identifier; static_symbol.type=component.type(); static_symbol.base_name=component.get(ID_base_name); static_symbol.lvalue=true; static_symbol.static_lifetime=true; static_symbol.location=cpp_name.location(); static_symbol.is_extern=true; // TODO: not sure about this: should be defined separately! dynamic_initializations.push_back(static_symbol.name); symbolt *new_symbol; if(context.move(static_symbol, new_symbol)) { err_location(cpp_name.location()); str << "redeclaration of static member `" << static_symbol.base_name.as_string() << "'"; throw 0; } if(value.is_not_nil()) { if(cpp_is_pod(new_symbol->type)) { new_symbol->value.swap(value); c_typecheck_baset::do_initializer(*new_symbol); // these are macros if they are PODs and come with a (constant) value if(new_symbol->type.get_bool(ID_C_constant)) { simplify(new_symbol->value, *this); new_symbol->is_macro=true; } } else { symbol_exprt symexpr; symexpr.set_identifier(new_symbol->name); exprt::operandst ops; ops.push_back(value); codet defcode = cpp_constructor(locationt(), symexpr, ops); new_symbol->value.swap(defcode); } } } // array members must have fixed size check_fixed_size_array(component.type()); put_compound_into_scope(component); components.push_back(component); }
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_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_custom_type(typet &type) { // they all have a width exprt size_expr= static_cast<const exprt &>(type.find(ID_size)); typecheck_expr(size_expr); make_constant_index(size_expr); mp_integer size_int; if(to_integer(size_expr, size_int)) { err_location(size_expr); throw "failed to convert bit vector width to constant"; } if(size_int<1 || size_int>1024) { err_location(size_expr); error("bit vector width invalid"); throw 0; } type.remove(ID_size); type.set(ID_width, integer2string(size_int)); // depending on type, there may be a number of fractional bits if(type.id()==ID_custom_unsignedbv) type.id(ID_unsignedbv); else if(type.id()==ID_custom_signedbv) type.id(ID_signedbv); else if(type.id()==ID_custom_fixedbv) { type.id(ID_fixedbv); exprt f_expr= static_cast<const exprt &>(type.find(ID_f)); locationt location=f_expr.find_location(); typecheck_expr(f_expr); make_constant_index(f_expr); mp_integer f_int; if(to_integer(f_expr, f_int)) { err_location(location); throw "failed to convert number of fraction bits to constant"; } if(f_int<0 || f_int>size_int) { err_location(location); error("fixedbv fraction width invalid"); throw 0; } type.remove(ID_f); type.set(ID_integer_bits, integer2string(size_int-f_int)); } else if(type.id()==ID_custom_floatbv) { type.id(ID_floatbv); exprt f_expr= static_cast<const exprt &>(type.find(ID_f)); locationt location=f_expr.find_location(); typecheck_expr(f_expr); make_constant_index(f_expr); mp_integer f_int; if(to_integer(f_expr, f_int)) { err_location(location); throw "failed to convert number of fraction bits to constant"; } if(f_int<1 || f_int+1>=size_int) { err_location(location); error("floatbv fraction width invalid"); throw 0; } type.remove(ID_f); type.set(ID_f, integer2string(f_int)); } else assert(false); }
void c_typecheck_baset::add_argc_argv(const symbolt &main_symbol) { const irept &arguments=main_symbol.type.arguments(); if(arguments.get_sub().size()==0) return; if(arguments.get_sub().size()!=2 && arguments.get_sub().size()!=3) { err_location(main_symbol.location); throw "main expected to have no or two or three arguments"; } symbolt *argc_new_symbol; const exprt &op0=(exprt &)arguments.get_sub()[0]; const exprt &op1=(exprt &)arguments.get_sub()[1]; { symbolt argc_symbol; argc_symbol.base_name="argc"; argc_symbol.name="c::argc'"; argc_symbol.type=op0.type(); argc_symbol.static_lifetime=true; argc_symbol.lvalue=true; if(argc_symbol.type.id()!="signedbv" && argc_symbol.type.id()!="unsignedbv") { err_location(main_symbol.location); str << "argc argument expected to be integer type, but got `" << to_string(argc_symbol.type) << "'"; throw 0; } move_symbol(argc_symbol, argc_new_symbol); } { if(op1.type().id()!="pointer" || op1.type().subtype().id()!="pointer") { err_location(main_symbol.location); str << "argv argument expected to be pointer-to-pointer type, " "but got `" << to_string(op1.type()) << "'"; throw 0; } // we make the type of this thing an array of pointers typet argv_type=array_typet(); argv_type.subtype()=op1.type().subtype(); // need to add one to the size -- the array is terminated // with NULL exprt one_expr=from_integer(1, argc_new_symbol->type); exprt size_expr("+", argc_new_symbol->type); size_expr.copy_to_operands(symbol_expr(*argc_new_symbol), one_expr); argv_type.size(size_expr); symbolt argv_symbol; argv_symbol.base_name="argv"; argv_symbol.name="c::argv'"; argv_symbol.type=argv_type; argv_symbol.static_lifetime=true; argv_symbol.lvalue=true; symbolt *argv_new_symbol; move_symbol(argv_symbol, argv_new_symbol); } if (arguments.get_sub().size()==3) { symbolt envp_symbol; envp_symbol.base_name="envp"; envp_symbol.name="c::envp'"; envp_symbol.type=(static_cast<const exprt&>(arguments.get_sub()[2])).type(); envp_symbol.static_lifetime=true; symbolt envp_size_symbol, *envp_new_size_symbol; envp_size_symbol.base_name="envp_size"; envp_size_symbol.name="c::envp_size'"; envp_size_symbol.type=op0.type(); // same type as argc! envp_size_symbol.static_lifetime=true; move_symbol(envp_size_symbol, envp_new_size_symbol); if(envp_symbol.type.id()!="pointer") { err_location(main_symbol.location); str << "envp argument expected to be pointer type, but got `" << to_string(envp_symbol.type) << "'"; throw 0; } exprt size_expr = symbol_expr(*envp_new_size_symbol); envp_symbol.type.id("array"); envp_symbol.type.size(size_expr); symbolt *envp_new_symbol; move_symbol(envp_symbol, envp_new_symbol); } }
void c_typecheck_baset::typecheck_code_type(code_typet &type) { code_typet::parameterst ¶meters=type.parameters(); // if we don't have any parameters, we assume it's (...) if(parameters.empty()) { type.make_ellipsis(); } else { // we do have parameters parameter_map.clear(); for(unsigned i=0; i<type.parameters().size(); i++) { code_typet::parametert ¶meter=type.parameters()[i]; // first fix type typet &type=parameter.type(); typecheck_type(type); adjust_function_parameter(type); // adjust the identifier irep_idt identifier=parameter.get_identifier(); if(identifier!=irep_idt()) { identifier=add_language_prefix(identifier); id_replace_mapt::const_iterator m_it=id_replace_map.find(identifier); if(m_it!=id_replace_map.end()) identifier=m_it->second; parameter.set_identifier(identifier); // make visible now, later parameters might use it parameter_map[identifier]=type; } } parameter_map.clear(); if(parameters.size()==1 && follow(parameters[0].type()).id()==ID_empty) { // if we just have one parameter of type void, remove it parameters.clear(); } } typecheck_type(type.return_type()); // 6.7.6.3: // "A function declarator shall not specify a return type that // is a function type or an array type." const typet &return_type=follow(type.return_type()); if(return_type.id()==ID_array) { err_location(type); throw "function must not return array"; } if(return_type.id()==ID_code) { err_location(type); throw "function must not return function type"; } }
void cpp_typecheckt::convert(cpp_namespace_spect &namespace_spec) { // save the scope cpp_save_scopet saved_scope(cpp_scopes); const irep_idt &name=namespace_spec.get_namespace(); if(name=="") { // "unique namespace" err_location(namespace_spec); throw "unique namespace not supported yet"; } irep_idt final_name(name); std::string identifier= cpp_identifier_prefix(current_mode)+"::"+ cpp_scopes.current_scope().prefix+id2string(final_name); contextt::symbolst::const_iterator it= context.symbols.find(identifier); if(it!=context.symbols.end()) { if(namespace_spec.alias().is_not_nil()) { err_location(namespace_spec); str << "namespace alias `" << final_name << "' previously declared" << std::endl; str << "location of previous declaration: " << it->second.location; throw 0; } if(it->second.type.id()!="namespace") { err_location(namespace_spec); str << "namespace `" << final_name << "' previously declared" << std::endl; str << "location of previous declaration: " << it->second.location; throw 0; } // enter that scope cpp_scopes.set_scope(it->first); } else { symbolt symbol; symbol.name=identifier; symbol.base_name=final_name; symbol.value.make_nil(); symbol.location=namespace_spec.location(); symbol.mode=current_mode; symbol.module=module; symbol.type=typet("namespace"); if(context.move(symbol)) throw "cpp_typecheckt::convert_namespace: context.move() failed"; cpp_scopes.new_namespace(final_name); } /*if(namespace_spec.alias().is_not_nil()) { cpp_typecheck_resolvet resolver(*this); cpp_scopet &s=resolver.resolve_namespace(namespace_spec.alias()); cpp_scopes.current_scope().add_using_scope(s); } else {*/ // do the declarations for(cpp_namespace_spect::itemst::iterator it=namespace_spec.items().begin(); it!=namespace_spec.items().end(); it++) convert(*it); // } }