예제 #1
0
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;
}
예제 #2
0
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);
  }
예제 #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(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
  }
}
예제 #4
0
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;
}
예제 #5
0
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;
  }
}
예제 #6
0
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);
}
예제 #8
0
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);
}
예제 #12
0
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);
}
예제 #13
0
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;
  }
}
예제 #14
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);
}
예제 #15
0
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);
  }
}
예제 #16
0
void c_typecheck_baset::typecheck_code_type(code_typet &type)
{
  code_typet::parameterst &parameters=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 &parameter=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";
  }
}
예제 #17
0
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);
//  }
}