Esempio n. 1
0
void cpp_typecheckt::convert(cpp_usingt &cpp_using)
{
  // there are two forms of using clauses:
  // a) using namespace SCOPE;  ("using directive")
  // b) using SCOPE::id;        ("using declaration")
  
  cpp_typecheck_resolvet resolver(*this);
  cpp_save_scopet save_scope(this->cpp_scopes);

  irep_idt base_name;
  cpp_template_args_non_tct template_args;
  resolver.resolve_scope(cpp_using.name(), base_name, template_args);

  bool qualified=cpp_using.name().is_qualified();
  cpp_scopest::id_sett id_set;

  cpp_scopes.current_scope().lookup(
    base_name, qualified?cpp_scopet::QUALIFIED:cpp_scopet::RECURSIVE, id_set);
    
  bool using_directive=cpp_using.get_namespace();

  if(id_set.empty())
  {
    error().source_location=cpp_using.name().source_location();
    error() << "using "
            << (using_directive?"namespace":"identifier")
            << " `"
            << base_name << "' not found" << eom;
    throw 0;
  }

  // go back to where we used to be
  save_scope.restore();

  for(cpp_scopest::id_sett::iterator
      it=id_set.begin();
      it!=id_set.end();
      it++)
  {
    if(using_directive)
    {
      if((*it)->id_class==cpp_idt::NAMESPACE)
        cpp_scopes.current_scope().add_using_scope(static_cast<cpp_scopet &>(**it));
      else
      {
        // we should likely complain about this
      }
    }
    else // declaration
    {
      // we copy all 'normal' identifiers into the current scope
      if((*it)->id_class!=cpp_idt::TEMPLATE_PARAMETER &&
         (*it)->id_class!=cpp_idt::NAMESPACE)
        cpp_scopes.current_scope().insert(**it);
    }
  }
}
Esempio n. 2
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;
    }
}
Esempio n. 3
0
codet cpp_typecheckt::cpp_constructor(
  const source_locationt &source_location,
  const exprt &object,
  const exprt::operandst &operands)
{
  exprt object_tc=object;

  typecheck_expr(object_tc);

  elaborate_class_template(object_tc.type());

  typet tmp_type(object_tc.type());
  follow_symbol(tmp_type);

  assert(!is_reference(tmp_type));

  if(tmp_type.id()==ID_array)
  {
    // We allow only one operand and it must be tagged with '#array_ini'.
    // Note that the operand is an array that is used for copy-initialization.
    // In the general case, a program is not allow to use this form of
    // construct. This way of initializing an array is used internaly only.
    // The purpose of the tag #arra_ini is to rule out ill-formed
    // programs.

    if(!operands.empty() && !operands.front().get_bool("#array_ini"))
    {
      error().source_location=source_location;
      error() << "bad array initializer" << eom;
      throw 0;
    }

    assert(operands.empty() || operands.size()==1);

    if(operands.empty() && cpp_is_pod(tmp_type))
    {
      codet nil;
      nil.make_nil();
      return nil;
    }

    const exprt &size_expr=
      to_array_type(tmp_type).size();

    if(size_expr.id()=="infinity")
    {
      // don't initialize
      codet nil;
      nil.make_nil();
      return nil;
    }

    exprt tmp_size=size_expr;
    make_constant_index(tmp_size);

    mp_integer s;
    if(to_integer(tmp_size, s))
    {
      error().source_location=source_location;
      error() << "array size `" << to_string(size_expr)
              << "' is not a constant" << eom;
      throw 0;
    }

    /*if(cpp_is_pod(tmp_type))
    {
      code_expressiont new_code;
      exprt op_tc=operands.front();
      typecheck_expr(op_tc);
       // Override constantness
      object_tc.type().set("#constant", false);
      object_tc.set("#lvalue", true);
      side_effect_exprt assign("assign");
      assign.add_source_location()=source_location;
      assign.copy_to_operands(object_tc, op_tc);
      typecheck_side_effect_assignment(assign);
      new_code.expression()=assign;
      return new_code;
    }
    else*/
    {
      codet new_code(ID_block);

      // for each element of the array, call the default constructor
      for(mp_integer i=0; i < s; ++i)
      {
        exprt::operandst tmp_operands;

        exprt constant=from_integer(i, index_type());
        constant.add_source_location()=source_location;

        exprt index(ID_index);
        index.copy_to_operands(object);
        index.copy_to_operands(constant);
        index.add_source_location()=source_location;

        if(!operands.empty())
        {
          exprt operand(ID_index);
          operand.copy_to_operands(operands.front());
          operand.copy_to_operands(constant);
          operand.add_source_location()=source_location;
          tmp_operands.push_back(operand);
        }

        exprt i_code =
          cpp_constructor(source_location, index, tmp_operands);

        if(i_code.is_nil())
        {
          new_code.is_nil();
          break;
        }

        new_code.move_to_operands(i_code);
      }
      return new_code;
    }
  }
  else if(cpp_is_pod(tmp_type))
  {
    code_expressiont new_code;
    exprt::operandst operands_tc=operands;

    for(exprt::operandst::iterator
      it=operands_tc.begin();
      it!=operands_tc.end();
      it++)
    {
      typecheck_expr(*it);
      add_implicit_dereference(*it);
    }

    if(operands_tc.empty())
    {
      // a POD is NOT initialized
      new_code.make_nil();
    }
    else if(operands_tc.size()==1)
    {
      // Override constantness
      object_tc.type().set(ID_C_constant, false);
      object_tc.set(ID_C_lvalue, true);
      side_effect_exprt assign(ID_assign);
      assign.add_source_location()=source_location;
      assign.copy_to_operands(object_tc, operands_tc.front());
      typecheck_side_effect_assignment(assign);
      new_code.expression()=assign;
    }
    else
    {
      error().source_location=source_location;
      error() << "initialization of POD requires one argument, "
                 "but got " << operands.size() << eom;
      throw 0;
    }

    return new_code;
  }
  else if(tmp_type.id()==ID_union)
  {
    assert(0); // Todo: union
  }
  else if(tmp_type.id()==ID_struct)
  {
    exprt::operandst operands_tc=operands;

    for(exprt::operandst::iterator
      it=operands_tc.begin();
      it!=operands_tc.end();
      it++)
    {
      typecheck_expr(*it);
      add_implicit_dereference(*it);
    }

    const struct_typet &struct_type=
      to_struct_type(tmp_type);

    // set most-derived bits
    codet block(ID_block);
    for(std::size_t i=0; i < struct_type.components().size(); i++)
    {
      const irept &component=struct_type.components()[i];
      if(component.get(ID_base_name)!="@most_derived")
        continue;

      exprt member(ID_member, bool_typet());
      member.set(ID_component_name, component.get(ID_name));
      member.copy_to_operands(object_tc);
      member.add_source_location()=source_location;
      member.set(ID_C_lvalue, object_tc.get_bool(ID_C_lvalue));

      exprt val=false_exprt();

      if(!component.get_bool("from_base"))
        val=true_exprt();

      side_effect_exprt assign(ID_assign);
      assign.add_source_location()=source_location;
      assign.move_to_operands(member, val);
      typecheck_side_effect_assignment(assign);
      code_expressiont code_exp;
      code_exp.expression()=assign;
      block.move_to_operands(code_exp);
    }

    // enter struct scope
    cpp_save_scopet save_scope(cpp_scopes);
    cpp_scopes.set_scope(struct_type.get(ID_name));

    // find name of constructor
    const struct_typet::componentst &components=
      struct_type.components();

    irep_idt constructor_name;

    for(struct_typet::componentst::const_iterator
        it=components.begin();
        it!=components.end();
        it++)
    {
      const typet &type=it->type();

      if(!it->get_bool(ID_from_base) &&
         type.id()==ID_code &&
         type.find(ID_return_type).id()==ID_constructor)
      {
        constructor_name=it->get(ID_base_name);
        break;
      }
    }

    // there is always a constructor for non-PODs
    assert(constructor_name!="");

    irept cpp_name(ID_cpp_name);
    cpp_name.get_sub().push_back(irept(ID_name));
    cpp_name.get_sub().back().set(ID_identifier, constructor_name);
    cpp_name.get_sub().back().set(ID_C_source_location, source_location);

    side_effect_expr_function_callt function_call;
    function_call.add_source_location()=source_location;
    function_call.function().swap(static_cast<exprt&>(cpp_name));
    function_call.arguments().reserve(operands_tc.size());

    for(exprt::operandst::iterator
        it=operands_tc.begin();
        it!=operands_tc.end();
        it++)
      function_call.op1().copy_to_operands(*it);

    typecheck_side_effect_function_call(function_call);
    assert(function_call.get(ID_statement)==ID_temporary_object);

    exprt &initializer =
      static_cast<exprt &>(function_call.add(ID_initializer));

    assert(initializer.id()==ID_code &&
           initializer.get(ID_statement)==ID_expression);

    side_effect_expr_function_callt &func_ini=
      to_side_effect_expr_function_call(initializer.op0());

    exprt &tmp_this=func_ini.arguments().front();
    assert(tmp_this.id()==ID_address_of
           && tmp_this.op0().id()=="new_object");

    exprt address_of(ID_address_of, typet(ID_pointer));
    address_of.type().subtype()=object_tc.type();
    address_of.copy_to_operands(object_tc);
    tmp_this.swap(address_of);

    if(block.operands().empty())
      return to_code(initializer);
    else
    {
      block.move_to_operands(initializer);
      return block;
    }
  }
  else
    assert(false);

  codet nil;
  nil.make_nil();
  return nil;
}