예제 #1
0
void c_typecheck_baset::typecheck_c_enum_tag_type(c_enum_tag_typet &type)
{
  // It's just a tag.

  if(type.find(ID_tag).is_nil())
  {
    error().source_location=type.source_location();
    error() << "anonymous enum tag without members" << eom;
    throw 0;
  }

  source_locationt source_location=type.source_location();

  irept &tag=type.add(ID_tag);
  irep_idt base_name=tag.get(ID_C_base_name);
  irep_idt identifier=tag.get(ID_identifier);

  // is it in the symbol table?
  symbol_tablet::symbolst::const_iterator s_it=
    symbol_table.symbols.find(identifier);

  if(s_it!=symbol_table.symbols.end())
  {
    // Yes.
    const symbolt &symbol=s_it->second;

    if(symbol.type.id()!=ID_c_enum &&
       symbol.type.id()!=ID_incomplete_c_enum)
    {
      error().source_location=source_location;
      error() << "use of tag that does not match previous declaration" << eom;
      throw 0;
    }
  }
  else
  {
    // no, add it as an incomplete c_enum
    typet new_type(ID_incomplete_c_enum);
    new_type.subtype()=signed_int_type(); // default
    new_type.add(ID_tag)=tag;

    symbolt enum_tag_symbol;

    enum_tag_symbol.is_type=true;
    enum_tag_symbol.type=new_type;
    enum_tag_symbol.location=source_location;
    enum_tag_symbol.is_file_local=true;
    enum_tag_symbol.base_name=base_name;
    enum_tag_symbol.name=identifier;

    symbolt *new_symbol;
    move_symbol(enum_tag_symbol, new_symbol);
  }

  // Clean up resulting type
  type.remove(ID_tag);
  type.set_identifier(identifier);
}
예제 #2
0
void c_typecheck_baset::typecheck_symbol(symbolt &symbol)
{
  current_symbol_id=symbol.name;

  bool is_function=symbol.type.id()==ID_code;

  const typet &final_type=follow(symbol.type);
  
  // set a few flags
  symbol.is_lvalue=!symbol.is_type && !symbol.is_macro;
  
  irep_idt root_name=symbol.base_name;
  irep_idt new_name=symbol.name;

  if(symbol.is_file_local)
  {
    // file-local stuff -- stays as is
    // collisions are resolved during linking
  }
  else if(symbol.is_extern && !is_function)
  {
    // variables marked as "extern" go into the global namespace
    // and have static lifetime
    new_name=root_name;
    symbol.is_static_lifetime=true;
  }
  else if(!is_function && symbol.value.id()==ID_code)
  {
    err_location(symbol.value);
    throw "only functions can have a function body";
  }
  
  // set the pretty name
  if(symbol.is_type &&
     (final_type.id()==ID_struct ||
      final_type.id()==ID_incomplete_struct))
  {
    symbol.pretty_name="struct "+id2string(symbol.base_name);
  }
  else if(symbol.is_type &&
          (final_type.id()==ID_union ||
           final_type.id()==ID_incomplete_union))
  {
    symbol.pretty_name="union "+id2string(symbol.base_name);
  }
  else if(symbol.is_type &&
          (final_type.id()==ID_c_enum ||
           final_type.id()==ID_incomplete_c_enum))
  {
    symbol.pretty_name="enum "+id2string(symbol.base_name);
  }
  else
  {
    symbol.pretty_name=new_name;
  }
  
  // see if we have it already
  symbol_tablet::symbolst::iterator old_it=symbol_table.symbols.find(symbol.name);
  
  if(old_it==symbol_table.symbols.end())
  {
    // just put into symbol_table
    symbolt *new_symbol;
    move_symbol(symbol, new_symbol);
    
    typecheck_new_symbol(*new_symbol);
  }    
  else
  {
    if(old_it->second.is_type!=symbol.is_type)
    {
      err_location(symbol.location);
      str << "redeclaration of `" << symbol.display_name()
          << "' as a different kind of symbol";
      throw 0;
    }

    if(symbol.is_type)
      typecheck_redefinition_type(old_it->second, symbol);
    else
      typecheck_redefinition_non_type(old_it->second, symbol);
  }
}
예제 #3
0
void c_typecheck_baset::typecheck_function_body(symbolt &symbol)
{
  code_typet &code_type=to_code_type(symbol.type);
  
  assert(symbol.value.is_not_nil());
  
  // reset labels
  labels_used.clear();
  labels_defined.clear();

  // fix type
  symbol.value.type()=code_type;
    
  // set return type
  return_type=code_type.return_type();
  
  unsigned anon_counter=0;
  
  // Add the parameter declarations into the symbol table.
  code_typet::parameterst &parameters=code_type.parameters();
  for(code_typet::parameterst::iterator
      p_it=parameters.begin();
      p_it!=parameters.end();
      p_it++)
  {
    // may be anonymous
    if(p_it->get_base_name()==irep_idt())
    {
      irep_idt base_name="#anon"+i2string(anon_counter++);
      p_it->set_base_name(base_name);
    }
    
    // produce identifier
    irep_idt base_name=p_it->get_base_name();
    irep_idt identifier=id2string(symbol.name)+"::"+id2string(base_name);

    p_it->set_identifier(identifier);

    parameter_symbolt p_symbol;
    
    p_symbol.type=p_it->type();
    p_symbol.name=identifier;
    p_symbol.base_name=base_name;
    p_symbol.location=p_it->source_location();

    symbolt *new_p_symbol;
    move_symbol(p_symbol, new_p_symbol);
  }

  // typecheck the body code  
  typecheck_code(to_code(symbol.value));

  // special case for main()  
  if(symbol.name==ID_main)
    add_argc_argv(symbol);

  // check the labels
  for(std::map<irep_idt, source_locationt>::const_iterator
      it=labels_used.begin(); it!=labels_used.end(); it++)
  {
    if(labels_defined.find(it->first)==labels_defined.end())
    {
      err_location(it->second);
      str << "branching label `" << it->first
          << "' is not defined in function";
      throw 0;
    }
  }
}
예제 #4
0
void c_typecheck_baset::add_argc_argv(const symbolt &main_symbol)
{
  const irept &arguments=
    main_symbol.type.find(ID_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=static_cast<const exprt &>(arguments.get_sub()[0]);
  const exprt &op1=static_cast<const 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.is_static_lifetime=true;
    argc_symbol.is_lvalue=true;

    if(argc_symbol.type.id()!=ID_signedbv &&
       argc_symbol.type.id()!=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()!=ID_pointer ||
       op1.type().subtype().id()!=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(ID_plus, argc_new_symbol->type);
    size_expr.copy_to_operands(symbol_expr(*argc_new_symbol), one_expr);
    argv_type.add(ID_size).swap(size_expr);

    symbolt argv_symbol;

    argv_symbol.base_name="argv'";
    argv_symbol.name="c::argv'";
    argv_symbol.type=argv_type;
    argv_symbol.is_static_lifetime=true;
    argv_symbol.is_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.is_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.is_static_lifetime=true;    
    move_symbol(envp_size_symbol, envp_new_size_symbol);        

    if(envp_symbol.type.id()!=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(ID_array);
    envp_symbol.type.add(ID_size).swap(size_expr);
    
    symbolt *envp_new_symbol;
    move_symbol(envp_symbol, envp_new_symbol);
  }
}
예제 #5
0
void c_typecheck_baset::typecheck_compound_type(struct_union_typet &type)
{
  // These get replaced by symbol types later.
  irep_idt identifier;

  bool have_body=type.find(ID_components).is_not_nil();

  if(type.find(ID_tag).is_nil())
  {
    // Anonymous? Must come with body.
    assert(have_body);

    // produce symbol
    symbolt compound_symbol;
    compound_symbol.is_type=true;
    compound_symbol.type=type;
    compound_symbol.location=type.source_location();

    typecheck_compound_body(to_struct_union_type(compound_symbol.type));

    std::string typestr=type2name(compound_symbol.type);
    compound_symbol.base_name="#anon-"+typestr;
    compound_symbol.name="tag-#anon#"+typestr;
    identifier=compound_symbol.name;

    // We might already have the same anonymous union/struct,
    // and this is simply ok. Note that the C standard treats
    // these as different types.
    if(symbol_table.symbols.find(identifier)==symbol_table.symbols.end())
    {
      symbolt *new_symbol;
      move_symbol(compound_symbol, new_symbol);
    }
  }
  else
  {
    identifier=type.find(ID_tag).get(ID_identifier);

    // does it exist already?
    symbol_tablet::symbolst::iterator s_it=
      symbol_table.symbols.find(identifier);

    if(s_it==symbol_table.symbols.end())
    {
      // no, add new symbol
      irep_idt base_name=type.find(ID_tag).get(ID_C_base_name);
      type.remove(ID_tag);
      type.set(ID_tag, base_name);

      symbolt compound_symbol;
      compound_symbol.is_type=true;
      compound_symbol.name=identifier;
      compound_symbol.base_name=base_name;
      compound_symbol.type=type;
      compound_symbol.location=type.source_location();
      compound_symbol.pretty_name=id2string(type.id())+" "+id2string(base_name);

      typet new_type=compound_symbol.type;

      if(compound_symbol.type.id()==ID_struct)
        compound_symbol.type.id(ID_incomplete_struct);
      else if(compound_symbol.type.id()==ID_union)
        compound_symbol.type.id(ID_incomplete_union);
      else
        assert(false);

      symbolt *new_symbol;
      move_symbol(compound_symbol, new_symbol);

      if(have_body)
      {
        typecheck_compound_body(to_struct_union_type(new_type));

        new_symbol->type.swap(new_type);
      }
    }
    else
    {
      // yes, it exists already
      if(s_it->second.type.id()==ID_incomplete_struct ||
         s_it->second.type.id()==ID_incomplete_union)
      {
        // Maybe we got a body now.
        if(have_body)
        {
          irep_idt base_name=type.find(ID_tag).get(ID_C_base_name);
          type.remove(ID_tag);
          type.set(ID_tag, base_name);

          typecheck_compound_body(type);
          s_it->second.type.swap(type);
        }
      }
      else if(have_body)
      {
        error().source_location=type.source_location();
        error() << "redefinition of body of `"
                << s_it->second.pretty_name << "'" << eom;
        throw 0;
      }
    }
  }

  symbol_typet symbol_type;
  symbol_type.add_source_location()=type.source_location();
  symbol_type.set_identifier(identifier);

  c_qualifierst original_qualifiers(type);
  type.swap(symbol_type);
  original_qualifiers.write(type);
}
예제 #6
0
void c_typecheck_baset::typecheck_c_enum_type(typet &type)
{
  // These come with the declarations
  // of the enum constants as operands.

  exprt &as_expr=static_cast<exprt &>(static_cast<irept &>(type));
  source_locationt source_location=type.source_location();

  // We allow empty enums in the grammar to get better
  // error messages.
  if(as_expr.operands().empty())
  {
    error().source_location=source_location;
    error() << "empty enum" << eom;
    throw 0;
  }

  // enums start at zero;
  // we also track min and max to find a nice base type
  mp_integer value=0, min_value=0, max_value=0;

  std::list<c_enum_typet::c_enum_membert> enum_members;

  // We need to determine a width, and a signedness
  // to obtain an 'underlying type'.
  // We just do int, but gcc might pick smaller widths
  // if the type is marked as 'packed'.
  // gcc/clang may also pick a larger width. Visual Studio doesn't.

  for(auto &op : as_expr.operands())
  {
    ansi_c_declarationt &declaration=to_ansi_c_declaration(op);
    exprt &v=declaration.declarator().value();

    if(v.is_not_nil()) // value given?
    {
      exprt tmp_v=v;
      typecheck_expr(tmp_v);
      add_rounding_mode(tmp_v);
      simplify(tmp_v, *this);
      if(tmp_v.is_true())
        value=1;
      else if(tmp_v.is_false())
        value=0;
      else if(!to_integer(tmp_v, value))
      {
      }
      else
      {
        error().source_location=v.source_location();
        error() << "enum is not a constant";
        throw 0;
      }
    }

    if(value<min_value)
      min_value=value;
    if(value>max_value)
      max_value=value;

    typet constant_type=
      enum_constant_type(min_value, max_value);

    v=from_integer(value, constant_type);

    declaration.type()=constant_type;
    typecheck_declaration(declaration);

    irep_idt base_name=
      declaration.declarator().get_base_name();

    irep_idt identifier=
      declaration.declarator().get_name();

    // store
    c_enum_typet::c_enum_membert member;
    member.set_identifier(identifier);
    member.set_base_name(base_name);
    member.set_value(integer2string(value));
    enum_members.push_back(member);

    // produce value for next constant
    ++value;
  }

  // Remove these now; we add them to the
  // c_enum symbol later.
  as_expr.operands().clear();

  bool is_packed=type.get_bool(ID_C_packed);

  // tag?
  if(type.find(ID_tag).is_nil())
  {
    // None, it's anonymous. We generate a tag.
    std::string anon_identifier="#anon_enum";

    for(const auto &member : enum_members)
    {
      anon_identifier+='$';
      anon_identifier+=id2string(member.get_base_name());
      anon_identifier+='=';
      anon_identifier+=id2string(member.get_value());
    }

    if(is_packed)
      anon_identifier+="#packed";

    type.add(ID_tag).set(ID_identifier, anon_identifier);
  }

  irept &tag=type.add(ID_tag);
  irep_idt base_name=tag.get(ID_C_base_name);
  irep_idt identifier=tag.get(ID_identifier);

  // Put into symbol table
  symbolt enum_tag_symbol;

  enum_tag_symbol.is_type=true;
  enum_tag_symbol.type=type;
  enum_tag_symbol.location=source_location;
  enum_tag_symbol.is_file_local=true;
  enum_tag_symbol.base_name=base_name;
  enum_tag_symbol.name=identifier;

  // throw in the enum members as 'body'
  irept::subt &body=enum_tag_symbol.type.add(ID_body).get_sub();

  for(const auto &member : enum_members)
    body.push_back(member);

  // We use a subtype to store the underlying type.
  typet underlying_type=
    enum_underlying_type(min_value, max_value, is_packed);

  enum_tag_symbol.type.subtype()=underlying_type;

  // is it in the symbol table already?
  symbol_tablet::symbolst::iterator s_it=
    symbol_table.symbols.find(identifier);

  if(s_it!=symbol_table.symbols.end())
  {
    // Yes.
    symbolt &symbol=s_it->second;

    if(symbol.type.id()==ID_incomplete_c_enum)
    {
      // Ok, overwrite the type in the symbol table.
      // This gives us the members and the subtype.
      symbol.type=enum_tag_symbol.type;
    }
    else if(symbol.type.id()==ID_c_enum)
    {
      // We might already have the same anonymous enum, and this is
      // simply ok. Note that the C standard treats these as
      // different types.
      if(!base_name.empty())
      {
        error().source_location=type.source_location();
        error() << "redeclaration of enum tag" << eom;
        throw 0;
      }
    }
    else
    {
      error().source_location=source_location;
      error() << "use of tag that does not match previous declaration" << eom;
      throw 0;
    }
  }
  else
  {
    symbolt *new_symbol;
    move_symbol(enum_tag_symbol, new_symbol);
  }

  // We produce a c_enum_tag as the resulting type.
  type.id(ID_c_enum_tag);
  type.remove(ID_tag);
  type.set(ID_identifier, identifier);
}