void c_typecheck_baset::increment_designator(designatort &designator) { assert(!designator.empty()); while(true) { designatort::entryt &entry=designator[designator.size()-1]; const typet &full_type=follow(entry.type); entry.index++; if(full_type.id()==ID_array && to_array_type(full_type).size().is_nil()) return; // we will keep going forever if(full_type.id()==ID_struct && entry.index<entry.size) { // need to adjust subtype const struct_typet &struct_type= to_struct_type(full_type); const struct_typet::componentst &components= struct_type.components(); assert(components.size()==entry.size); // we skip over any padding or code while(entry.index<entry.size && (components[entry.index].get_is_padding() || components[entry.index].type().id()==ID_code)) entry.index++; if(entry.index<entry.size) entry.subtype=components[entry.index].type(); } if(entry.index<entry.size) return; // done if(designator.size()==1) return; // done // pop entry designator.pop_entry(); assert(!designator.empty()); } }
void c_typecheck_baset::increment_designator(designatort &designator) { assert(!designator.empty()); while(true) { designatort::entryt &entry=designator[designator.size()-1]; entry.index++; if(entry.type.id()==ID_incomplete_array) return; // we will keep going forever if(entry.type.id()==ID_struct && entry.index<entry.size) { // need to adjust subtype const struct_typet &struct_type= to_struct_type(entry.type); const struct_typet::componentst &components= struct_type.components(); assert(components.size()==entry.size); // we skip over padding if(components[entry.index].get_is_padding()) entry.index++; if(entry.index<entry.size) entry.subtype=components[entry.index].type(); } if(entry.index<entry.size) return; // done if(designator.size()==1) return; // done // pop entry designator.pop_entry(); assert(!designator.empty()); } }
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 } }
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(unsigned i=0; i<designator.size(); i++) { unsigned index=designator[i].index; const typet &type=designator[i].type; assert(type.id()!=ID_symbol); if(type.id()==ID_array || type.id()==ID_struct || type.id()==ID_incomplete_array) { if(index>=dest->operands().size()) { if(type.id()==ID_incomplete_array) { exprt zero=zero_initializer(type.subtype(), value.location()); dest->operands().resize(integer2long(index)+1, zero); } else { err_location(value); str << "index designator " << index << " out of bounds (" << dest->operands().size() << ")"; throw 0; } } dest=&(dest->operands()[integer2long(index)]); } else if(type.id()==ID_union) { // union initialization is quite special const union_typet &union_type=to_union_type(type); const union_typet::componentt &component=union_type.components()[index]; // build a union expression from the argument exprt union_expr(ID_union, type); union_expr.operands().resize(1); union_expr.op0()=zero_initializer(component.type(), value.location()); union_expr.location()=value.location(); union_expr.set(ID_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 typet type=follow(designator.back().subtype); assert(type.id()!=ID_symbol); // do we initialize a scalar? if(type.id()!=ID_struct && type.id()!=ID_union && type.id()!=ID_array && type.id()!=ID_incomplete_array) { // 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(type==follow(dest->type())); return; // done } // 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((type.id()==ID_array || type.id()==ID_incomplete_array) && (follow(type.subtype()).id()==ID_signedbv || follow(type.subtype()).id()==ID_unsignedbv)) { *dest=do_initializer_rec(value, type, force_constant); return; // done } } else if(follow(value.type())==type) { // a struct/union can be initialized directly with // an expression of the right type. This doesn't // work with arrays, unfortunately. if(type.id()==ID_struct || type.id()==ID_union) { *dest=value; return; // done } } // we are initializing a compound type, and enter it! designator_enter(type, designator); assert(!dest->operands().empty()); dest=&(dest->op0()); // we run into another loop iteration } }