Esempio n. 1
0
void c_typecastt::implicit_typecast_followed(
  exprt &expr,
  const typet &src_type,
  const typet &dest_type)
{
  if(dest_type.id()==ID_union)

  // do transparent union
  if(dest_type.id()==ID_union &&
     dest_type.get_bool(ID_C_transparent_union) &&
     src_type.id()!=ID_union)
  {
    // The argument corresponding to a transparent union type can be of any
    // type in the union; no explicit cast is required.
    
    // Check union members.
    const union_typet &dest_union_type=to_union_type(dest_type);

    for(union_typet::componentst::const_iterator
        it=dest_union_type.components().begin();
        it!=dest_union_type.components().end();
        it++)
    {
      if(!check_c_implicit_typecast(src_type, it->type()))
      {
        // build union constructor
        exprt union_expr(ID_union, dest_union_type);
        union_expr.move_to_operands(expr);
        union_expr.set(ID_component_name, it->get_name());
        expr=union_expr;
        return; // ok
      }
    }
  }

  if(dest_type.id()==ID_pointer)
  {
    // special case: 0 == NULL

    if(expr.is_zero() && (
       src_type.id()==ID_unsignedbv ||
       src_type.id()==ID_signedbv ||
       src_type.id()==ID_natural ||
       src_type.id()==ID_integer))
    {
      expr=exprt(ID_constant, dest_type);
      expr.set(ID_value, ID_NULL);
      return; // ok
    }
  
    if(src_type.id()==ID_pointer ||
       src_type.id()==ID_array)
    {
      // we are quite generous about pointers
      
      const typet &src_sub=ns.follow(src_type.subtype());
      const typet &dest_sub=ns.follow(dest_type.subtype());

      if(is_void_pointer(src_type) ||
         is_void_pointer(dest_type))
      {
        // from/to void is always good
      }
      else if(src_sub.id()==ID_code &&
              dest_sub.id()==ID_code)
      {
        // very generous:
        // between any two function pointers it's ok
      }
      else if(base_type_eq(src_type.subtype(), dest_type.subtype(), ns))
      {
        // ok
      }
      else if((is_number(src_sub) || src_sub.id()==ID_c_enum) &&
              (is_number(dest_sub) || dest_sub.id()==ID_c_enum))
      {
        // Also generous: between any to scalar types it's ok.
        // We should probably check the size.
      }
      else
        warnings.push_back("incompatible pointer types");

      // check qualifiers

      /*
      if(src_type.subtype().get_bool(ID_C_constant) &&
         !dest_type.subtype().get_bool(ID_C_constant))
        warnings.push_back("disregarding const");
      */

      if(src_type.subtype().get_bool(ID_C_volatile) &&
         !dest_type.subtype().get_bool(ID_C_volatile))
        warnings.push_back("disregarding volatile");

      if(src_type==dest_type)
      {
        expr.type()=src_type; // because of qualifiers
      }
      else
        do_typecast(expr, dest_type);

      return; // ok
    }
  }
  
  if(check_c_implicit_typecast(src_type, dest_type))
    errors.push_back("implicit conversion not permitted");
  else if(src_type!=dest_type)
    do_typecast(expr, dest_type);
}
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
  }
}
Esempio n. 3
0
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
  }
}