Ejemplo n.º 1
0
symbolt &cpp_declarator_convertert::convert(
    const typet &declaration_type,
    const cpp_storage_spect &storage_spec,
    const cpp_member_spect &member_spec,
    cpp_declaratort &declarator)
{
    assert(declaration_type.is_not_nil());

    if(declaration_type.id()=="cpp-cast-operator")
    {
        typet type;
        type.swap(declarator.name().get_sub().back());
        declarator.type().subtype()=type;
        std::string tmp;
        cpp_typecheck.typecheck_type(type);
        irept name(ID_name);
        name.set(ID_identifier, "("+cpp_type2name(type)+")");
        declarator.name().get_sub().back().swap(name);
    }

    assert(declarator.id()==ID_cpp_declarator);
    final_type=declarator.merge_type(declaration_type);
    assert(final_type.is_not_nil());

    cpp_template_args_non_tct template_args;

    // run resolver on scope
    {
        cpp_save_scopet save_scope(cpp_typecheck.cpp_scopes);

        cpp_typecheck_resolvet cpp_typecheck_resolve(cpp_typecheck);

        cpp_typecheck_resolve.resolve_scope(
            declarator.name(), base_name, template_args);

        scope=&cpp_typecheck.cpp_scopes.current_scope();

        // check the declarator-part of the type, in that scope
        cpp_typecheck.typecheck_type(final_type);
    }

    is_code=is_code_type(final_type);

    // global-scope arrays must have fixed size
    if(scope->is_global_scope())
        cpp_typecheck.check_fixed_size_array(final_type);

    get_final_identifier();

    // first see if it is a member
    if(scope->id_class==cpp_idt::CLASS && !is_friend)
    {
        // it's a member! it must be declared already

        typet &method_qualifier=
            static_cast<typet &>(declarator.method_qualifier());

        // adjust template type
        if(final_type.id()==ID_template)
        {
            assert(0);
            typet tmp;
            tmp.swap(final_type.subtype());
            final_type.swap(tmp);
        }

        // try static first
        symbol_tablet::symbolst::iterator c_it=
            cpp_typecheck.symbol_table.symbols.find(final_identifier);

        if(c_it==cpp_typecheck.symbol_table.symbols.end())
        {
            // adjust type if it's a non-static member function
            if(final_type.id()==ID_code)
                cpp_typecheck.adjust_method_type(
                    scope->identifier, final_type, method_qualifier);

            get_final_identifier();

            // try again
            c_it=cpp_typecheck.symbol_table.symbols.find(final_identifier);

            if(c_it==cpp_typecheck.symbol_table.symbols.end())
            {
                cpp_typecheck.err_location(declarator.name());
                cpp_typecheck.str << "member `" << base_name
                                  << "' not found in scope `"
                                  << scope->identifier << "'";
                throw 0;
            }
        }

        assert(c_it!=cpp_typecheck.symbol_table.symbols.end());

        symbolt &symbol=c_it->second;

        combine_types(declarator.name().source_location(), final_type, symbol);
        enforce_rules(symbol);

        // If it is a constructor, we take care of the
        // object initialization
        if(final_type.get(ID_return_type)==ID_constructor)
        {
            const cpp_namet &name=declarator.name();

            exprt symbol_expr=
                cpp_typecheck.resolve(
                    name,
                    cpp_typecheck_resolvet::TYPE,
                    cpp_typecheck_fargst());

            if(symbol_expr.id()!=ID_type ||
                    symbol_expr.type().id()!=ID_symbol)
            {
                cpp_typecheck.err_location(name.source_location());
                cpp_typecheck.str << "error: expected type";
                throw 0;
            }

            irep_idt identifier=symbol_expr.type().get(ID_identifier);
            const symbolt &symb=cpp_typecheck.lookup(identifier);
            const typet &type = symb.type;
            assert(type.id()==ID_struct);

            if(declarator.find(ID_member_initializers).is_nil())
                declarator.set(ID_member_initializers, ID_member_initializers);

            cpp_typecheck.check_member_initializers(
                type.find(ID_bases),
                to_struct_type(type).components(),
                declarator.member_initializers());

            cpp_typecheck.full_member_initialization(
                to_struct_type(type),
                declarator.member_initializers());
        }

        if(!storage_spec.is_extern())
            symbol.is_extern=false;

        // initializer?
        handle_initializer(symbol, declarator);

        return symbol;
    }
    else
    {
        // no, it's no way a method

        // we won't allow the constructor/destructor type
        if(final_type.id()==ID_code &&
                to_code_type(final_type).return_type().id()==ID_constructor)
        {
            cpp_typecheck.err_location(declarator.name().source_location());
            cpp_typecheck.str << "function must have return type";
            throw 0;
        }

        // already there?
        symbol_tablet::symbolst::iterator c_it=
            cpp_typecheck.symbol_table.symbols.find(final_identifier);

        if(c_it==cpp_typecheck.symbol_table.symbols.end())
            return convert_new_symbol(storage_spec, member_spec, declarator);

        symbolt &symbol=c_it->second;

        if(!storage_spec.is_extern())
            symbol.is_extern = false;

        if(declarator.get_bool("#template_case"))
            return symbol;

        combine_types(declarator.name().source_location(), final_type, symbol);
        enforce_rules(symbol);

        // initializer?
        handle_initializer(symbol, declarator);

        if(symbol.type.id()=="cpp-template-type")
        {
            cpp_scopet::id_sett id_set;

            scope->lookup_identifier(symbol.name, cpp_idt::TEMPLATE_PARAMETER, id_set);

            if(id_set.empty())
            {
                cpp_idt &identifier=
                    cpp_typecheck.cpp_scopes.put_into_scope(symbol,*scope);
                identifier.id_class=cpp_idt::TEMPLATE_PARAMETER;
            }
        }

        return symbol;
    }
}
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);
}