Exemplo n.º 1
0
void cpp_typecheckt::typecheck_enum_type(typet &type)
{
  // first save qualifiers
  c_qualifierst qualifiers;
  qualifiers.read(type);
  
  // these behave like special struct types
  // replace by type symbol
  
  cpp_enum_typet &enum_type=to_cpp_enum_type(type);
  bool anonymous=!enum_type.has_tag();
  irep_idt base_name;
  
  if(anonymous)
  {
    // we fabricate a tag based on the enum constants contained
    base_name=enum_type.generate_anon_tag();
  }
  else
  {
    const cpp_namet &tag=enum_type.tag();
    
    if(tag.is_simple_name())
      base_name=tag.get_base_name();
    else
    {
      err_location(type);
      throw "enum tag is expected to be a simple name";
    }
  }

  bool has_body=enum_type.has_body();
  bool tag_only_declaration=enum_type.get_tag_only_declaration();

  cpp_scopet &dest_scope=
    tag_scope(base_name, has_body, tag_only_declaration);

  const irep_idt symbol_name=
    dest_scope.prefix+"tag."+id2string(base_name);

  // check if we have it
  
  symbol_tablet::symbolst::iterator previous_symbol=
    symbol_table.symbols.find(symbol_name);
    
  if(previous_symbol!=symbol_table.symbols.end())
  {
    // we do!

    symbolt &symbol=previous_symbol->second;

    if(has_body)
    {
      err_location(type);
      str << "error: enum symbol `" << base_name
          << "' declared previously" << std::endl;
      str << "location of previous definition: "
          << symbol.location << std::endl;
      throw 0;
    }
  }
  else if(has_body)
  {
    std::string pretty_name=
      cpp_scopes.current_scope().prefix+id2string(base_name);

    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=pretty_name;
    
    // move early, must be visible before doing body
    symbolt *new_symbol;
    if(symbol_table.move(symbol, new_symbol))
      throw "cpp_typecheckt::typecheck_enum_type: symbol_table.move() failed";    

    // put into scope
    cpp_idt &scope_identifier=
      cpp_scopes.put_into_scope(*new_symbol, dest_scope);
    
    scope_identifier.id_class=cpp_idt::CLASS;

    typecheck_enum_body(*new_symbol);
  }
  else
  {
    err_location(type);
    str << "use of enum `" << base_name
        << "' without previous declaration";
    throw 0;
  }

  // create type symbol
  type=typet(ID_symbol);
  type.set(ID_identifier, symbol_name);
  qualifiers.write(type);
}
Exemplo n.º 2
0
void cpp_typecheckt::typecheck_enum_type(typet &type)
{
  // first save qualifiers
  c_qualifierst qualifiers;
  qualifiers.read(type);
  
  cpp_enum_typet &enum_type=to_cpp_enum_type(type);
  bool anonymous=!enum_type.has_tag();
  irep_idt base_name;
  
  if(anonymous)
  {
    // we fabricate a tag based on the enum constants contained
    base_name=enum_type.generate_anon_tag();
  }
  else
  {
    const cpp_namet &tag=enum_type.tag();
    
    if(tag.is_simple_name())
      base_name=tag.get_base_name();
    else
    {
      err_location(type);
      throw "enum tag is expected to be a simple name";
    }
  }

  bool has_body=enum_type.has_body();
  bool tag_only_declaration=enum_type.get_tag_only_declaration();

  cpp_scopet &dest_scope=
    tag_scope(base_name, has_body, tag_only_declaration);

  const irep_idt symbol_name=
    dest_scope.prefix+"tag-"+id2string(base_name);

  // check if we have it
  
  symbol_tablet::symbolst::iterator previous_symbol=
    symbol_table.symbols.find(symbol_name);
    
  if(previous_symbol!=symbol_table.symbols.end())
  {
    // we do!

    symbolt &symbol=previous_symbol->second;

    if(has_body)
    {
      err_location(type);
      str << "error: enum symbol `" << base_name
          << "' declared previously\n";
      str << "location of previous definition: "
          << symbol.location;
      throw 0;
    }
  }
  else if(has_body)
  {
    std::string pretty_name=
      cpp_scopes.current_scope().prefix+id2string(base_name);
      
    // C++11 enumerations have an underlying type,
    // which defaults to int.
    // enums without underlying type may be 'packed'.
    if(type.subtype().is_nil())
      type.subtype()=signed_int_type();
    else
    {
      typecheck_type(type.subtype());
      if(type.subtype().id()==ID_signedbv ||
         type.subtype().id()==ID_unsignedbv)
      {
      }
      else
      {
        err_location(type);
        str << "underlying type must be integral";
        throw 0;
      }
    }

    symbolt symbol;

    symbol.name=symbol_name;
    symbol.base_name=base_name;
    symbol.value.make_nil();
    symbol.location=type.source_location();
    symbol.mode=ID_cpp;
    symbol.module=module;
    symbol.type.swap(type);
    symbol.is_type=true;
    symbol.is_macro=false;
    symbol.pretty_name=pretty_name;
    
    // move early, must be visible before doing body
    symbolt *new_symbol;
    if(symbol_table.move(symbol, new_symbol))
      throw "cpp_typecheckt::typecheck_enum_type: symbol_table.move() failed";    

    // put into scope
    cpp_idt &scope_identifier=
      cpp_scopes.put_into_scope(*new_symbol, dest_scope);
    
    scope_identifier.id_class=cpp_idt::CLASS;

    typecheck_enum_body(*new_symbol);
  }
  else
  {
    err_location(type);
    str << "use of enum `" << base_name
        << "' without previous declaration";
    throw 0;
  }

  // create enum tag expression, and add the qualifiers
  type=c_enum_tag_typet(symbol_name);
  qualifiers.write(type);
}
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);
}