bool has_component_rec( const typet &type, const irep_idt &component_name, const namespacet &ns) { const struct_union_typet &struct_union_type= to_struct_union_type(ns.follow(type)); const struct_union_typet::componentst &components= struct_union_type.components(); for(struct_union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_name()==component_name) { return true; } else if(it->get_anonymous()) { if(has_component_rec(it->type(), component_name, ns)) return true; } } return false; }
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; }