Пример #1
0
void cpp_typecheckt::convert_function(symbolt &symbol)
{
  code_typet &function_type=
    to_code_type(template_subtype(symbol.type));

  // only a prototype?
  if(symbol.value.is_nil())
    return;

  // if it is a destructor, add the implicit code
  if(symbol.type.get(ID_return_type)==ID_destructor)
  {
    const symbolt &msymb=lookup(symbol.type.get(ID_C_member_name));

    assert(symbol.value.id()==ID_code);
    assert(symbol.value.get(ID_statement)==ID_block);

    symbol.value.copy_to_operands(dtor(msymb));
  }

  // enter appropriate scope
  cpp_save_scopet saved_scope(cpp_scopes);
  cpp_scopet &function_scope=cpp_scopes.set_scope(symbol.name);

  // fix the scope's prefix
  function_scope.prefix+=id2string(symbol.name)+"::";

  // genuine function definition -- do the parameter declarations
  convert_arguments(symbol.mode, function_type);

  // create "this" if it's a non-static method
  if(function_scope.is_method &&
     !function_scope.is_static_member)
  {
    code_typet::argumentst &arguments=function_type.arguments();
    assert(arguments.size()>=1);
    code_typet::argumentt &this_argument_expr=arguments.front();
    function_scope.this_expr=exprt(ID_symbol, this_argument_expr.type());
    function_scope.this_expr.set(ID_identifier, this_argument_expr.get(ID_C_identifier));
  }
  else
    function_scope.this_expr.make_nil();

  // do the function body
  start_typecheck_code();

  // save current return type
  typet old_return_type=return_type;

  return_type=function_type.return_type();

  // constructor, destructor?
  if(return_type.id()==ID_constructor ||
     return_type.id()==ID_destructor)
    return_type=empty_typet();
  
  typecheck_code(to_code(symbol.value));

  symbol.value.type()=symbol.type;
  
  return_type = old_return_type;
}
Пример #2
0
void cpp_typecheckt::convert_template_function_or_member_specialization(
  cpp_declarationt &declaration)
{
  cpp_save_scopet saved_scope(cpp_scopes);
  
  if(declaration.declarators().size()!=1 ||
     declaration.declarators().front().type().id()!=ID_function_type)
  {
    err_location(declaration.type());
    str << "expected function template specialization";
    throw 0;
  }

  assert(declaration.declarators().size()==1);
  cpp_declaratort declarator=declaration.declarators().front();
  cpp_namet &cpp_name=declarator.name();

  if(cpp_name.is_qualified())
  {
    err_location(cpp_name.source_location());
    str << "qualifiers not expected here";
    throw 0;
  }
  
  // There is specialization (instantiation with template arguments)
  // but also function overloading (no template arguments)
  
  assert(!cpp_name.get_sub().empty());
  
  if(cpp_name.get_sub().back().id()==ID_template_args)
  {
    // proper specialization with arguments
    if(cpp_name.get_sub().size()!=2 ||
       cpp_name.get_sub()[0].id()!=ID_name ||
       cpp_name.get_sub()[1].id()!=ID_template_args)
    {
      // currently we are more restrictive
      // than the standard
      err_location(cpp_name.source_location());
      str << "bad template-function-specialization name";
      throw 0;
    }

    std::string base_name=
      cpp_name.get_sub()[0].get(ID_identifier).c_str();

    cpp_scopest::id_sett id_set;
    cpp_scopes.current_scope().lookup(
      base_name, cpp_scopet::SCOPE_ONLY, id_set);

    if(id_set.empty())
    {
      err_location(cpp_name.source_location());
      str << "template function `" << base_name << "' not found";
      throw 0;
    }
    else if(id_set.size()>1)
    {
      err_location(cpp_name.source_location());
      str << "template function `" << base_name << "' is ambiguous";
    }
    
    const symbolt &template_symbol=
      lookup((*id_set.begin())->identifier);

    cpp_template_args_tct template_args=
      typecheck_template_args(
        declaration.source_location(),
        template_symbol,
        to_cpp_template_args_non_tc(cpp_name.get_sub()[1]));

    cpp_name.get_sub().pop_back();

    typet specialization;
    specialization.swap(declarator);

    instantiate_template(
      cpp_name.source_location(),
      template_symbol,
      template_args,
      template_args,
      specialization);
  }
  else
  {
    // Just overloading, but this is still a template
    // for disambiguation purposes!
    // http://www.gotw.ca/publications/mill17.htm
    cpp_declarationt new_declaration=declaration;
    
    new_declaration.remove(ID_template_type);
    new_declaration.remove(ID_is_template);
    new_declaration.set(ID_C_template, ""); // todo, get identifier
    
    convert_non_template_declaration(new_declaration);
  }
}
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);
    }
  }
Пример #4
0
void cpp_typecheckt::convert_class_template_specialization(
  cpp_declarationt &declaration)
{
  cpp_save_scopet saved_scope(cpp_scopes);

  typet &type=declaration.type();

  assert(type.id()==ID_struct);

  cpp_namet &cpp_name=
    static_cast<cpp_namet &>(type.add(ID_tag));

  if(cpp_name.is_qualified())
  {
    err_location(cpp_name.source_location());
    str << "qualifiers not expected here";
    throw 0;
  }
  
  if(cpp_name.get_sub().size()!=2 ||
     cpp_name.get_sub()[0].id()!=ID_name ||
     cpp_name.get_sub()[1].id()!=ID_template_args)
  {
    // currently we are more restrictive
    // than the standard
    err_location(cpp_name.source_location());
    str << "bad template-class-sepcialization name";                                                
    throw 0;
  }

  irep_idt base_name=
    cpp_name.get_sub()[0].get(ID_identifier);

  // copy the template arguments    
  const cpp_template_args_non_tct template_args_non_tc=
    to_cpp_template_args_non_tc(cpp_name.get_sub()[1]);

  // Remove the template arguments from the name.
  cpp_name.get_sub().pop_back();

  // get the template symbol

  cpp_scopest::id_sett id_set;
  cpp_scopes.current_scope().lookup(
    base_name, cpp_scopet::SCOPE_ONLY, cpp_idt::TEMPLATE, id_set);

  // remove any specializations
  for(cpp_scopest::id_sett::iterator
      it=id_set.begin();
      it!=id_set.end();
      ) // no it++
  {
    cpp_scopest::id_sett::iterator next=it;
    next++;
    
    if(lookup((*it)->identifier).type.
         find("specialization_of").is_not_nil())
      id_set.erase(it);
    
    it=next;
  }

  // only one should be left
  if(id_set.empty())
  {
    err_location(type.source_location());
    str << "class template `" << base_name << "' not found";
    throw 0;
  }
  else if(id_set.size()>1)
  {
    err_location(type);
    str << "class template `" << base_name << "' is ambiguous";
    throw 0;
  }
  
  symbol_tablet::symbolst::iterator s_it=
    symbol_table.symbols.find((*id_set.begin())->identifier);
    
  assert(s_it!=symbol_table.symbols.end());
  
  symbolt &template_symbol=s_it->second;
    
  if(!template_symbol.type.get_bool(ID_is_template))
  {
    err_location(type);
    str << "expected a template";
  }

  #if 0
  // is this partial specialization?  
  if(declaration.template_type().parameters().empty())
  {
    // typecheck arguments -- these are for the 'primary' template!
    cpp_template_args_tct template_args_tc=
      typecheck_template_args(
        declaration.source_location(),
        to_cpp_declaration(template_symbol.type).template_type(),
        template_args_non_tc);
    
    // Full specialization, i.e., template<>.
    // We instantiate.
    instantiate_template(
      cpp_name.source_location(),
      template_symbol,
      template_args_tc,
      type);
  }
  else
  #endif
  
  {
    // partial specialization -- we typecheck
    declaration.partial_specialization_args()=template_args_non_tc;
    declaration.set_specialization_of(template_symbol.name);

    typecheck_class_template(declaration);
  }
}
Пример #5
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);
//  }
}