Esempio n. 1
0
std::string cpp_typecheckt::class_template_identifier(
  const irep_idt &base_name,
  const template_typet &template_type,
  const cpp_template_args_non_tct &partial_specialization_args)
{
  std::string identifier=
    cpp_scopes.current_scope().prefix+
    "template."+id2string(base_name) + "<";

  int counter=0;

  // these are probably not needed -- templates
  // should be unique in a namespace
  for(template_typet::template_parameterst::const_iterator
      it=template_type.template_parameters().begin();
      it!=template_type.template_parameters().end();
      it++)
  {
    if(counter!=0) identifier+=',';
  
    if(it->id()==ID_type)
      identifier+="Type"+i2string(counter);
    else
      identifier+="Non_Type"+i2string(counter);

    counter++;
  }

  identifier += ">";
  
  if(!partial_specialization_args.arguments().empty())
  {
    identifier+="_specialized_to_<";
  
    counter=0;
    for(cpp_template_args_non_tct::argumentst::const_iterator
        it=partial_specialization_args.arguments().begin();
        it!=partial_specialization_args.arguments().end();
        it++, counter++)
    {  
      if(counter!=0) identifier+=',';
      
      // These are not yet typechecked, as they may depend
      // on unassigned template parameters.

      if(it->id()==ID_type || it->id()=="ambiguous")
        identifier+=cpp_type2name(it->type());
      else
        identifier+=cpp_expr2name(*it);
    }
    
    identifier+='>';
  }
  
  return identifier;
}
Esempio n. 2
0
std::string cpp_typecheckt::function_template_identifier(
  const irep_idt &base_name,
  const template_typet &template_type,
  const typet &function_type)
{
  // we first build something without function arguments
  cpp_template_args_non_tct partial_specialization_args;
  std::string identifier=
    class_template_identifier(base_name, template_type,
                              partial_specialization_args);

  // we must also add the signature of the function to the identifier
  identifier+=cpp_type2name(function_type);

  return identifier;
}
Esempio n. 3
0
irep_idt cpp_typecheckt::function_identifier(const typet &type)
{
  const code_typet &function_type=
    to_code_type(template_subtype(type));

  const code_typet::argumentst &arguments=
    function_type.arguments();

  std::string result;
  bool first=true;

  result+='(';

  // the name of the function should not depend on
  // the class name that is encoded in the type of this,
  // but we must distinguish "const" and "non-const" member
  // functions

  code_typet::argumentst::const_iterator it=
    arguments.begin();

  if(it!=arguments.end() &&
     it->get_identifier()==ID_this)
  {
    const typet &pointer=it->type();
    const typet &symbol =pointer.subtype();
    if(symbol.get_bool(ID_C_constant)) result+="const$";
    if(symbol.get_bool(ID_C_volatile)) result+="volatile$";
    result+="this";
    first=false;
    it++;
  }

  // we skipped the "this", on purpose!

  for(; it!=arguments.end(); it++)
  {
    if(first) first=false; else result+=",";
    typet tmp_type=it->type();
    result+=cpp_type2name(it->type());
  }

  result+=')';

  return result;
}
Esempio n. 4
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_declarator(
  const symbolt &symbol,
  const cpp_declarationt &declaration,
  cpp_declaratort &declarator,
  struct_typet::componentst &components,
  const irep_idt &access,
  bool is_static,
  bool is_typedef,
  bool is_mutable)
{
  bool is_cast_operator=
    declaration.type().id()=="cpp-cast-operator";

  if(is_cast_operator)
  {
    assert(declarator.name().get_sub().size()==2 &&
           declarator.name().get_sub().front().id()==ID_operator);

    typet type=static_cast<typet &>(declarator.name().get_sub()[1]);
    declarator.type().subtype()=type;

    irept name(ID_name);
    name.set(ID_identifier, "("+cpp_type2name(type)+")");
    declarator.name().get_sub().back().swap(name);
  }

  typet final_type=
    declarator.merge_type(declaration.type());

  // this triggers template elaboration
  elaborate_class_template(final_type);

  typecheck_type(final_type);
  
  cpp_namet cpp_name;
  cpp_name.swap(declarator.name());
  
  irep_idt base_name;
  
  if(cpp_name.is_nil())
  {
    // Yes, there can be members without name.
    base_name=irep_idt();
  }
  else if(cpp_name.is_simple_name())
  {
    base_name=cpp_name.get_base_name();
  }
  else
  {
    err_location(cpp_name.location());
    str << "declarator in compound needs to be simple name";
    throw 0;
  }


  bool is_method=!is_typedef && final_type.id()==ID_code;
  bool is_constructor=declaration.is_constructor();
  bool is_destructor=declaration.is_destructor();
  bool is_virtual=declaration.member_spec().is_virtual();
  bool is_explicit=declaration.member_spec().is_explicit();
  bool is_inline=declaration.member_spec().is_inline();

  final_type.set(ID_C_member_name, symbol.name);

  // first do some sanity checks

  if(is_virtual && !is_method)
  {
    err_location(cpp_name.location());
    str << "only methods can be virtual";
    throw 0;
  }

  if(is_inline && !is_method)
  {
    err_location(cpp_name.location());
    str << "only methods can be inlined";
    throw 0;
  }

  if(is_virtual && is_static)
  {
    err_location(cpp_name.location());
    str << "static methods cannot be virtual";
    throw 0;
  }

  if(is_cast_operator && is_static)
  {
    err_location(cpp_name.location());
    str << "cast operators cannot be static`";
    throw 0;
  }

  if(is_constructor && is_virtual)
  {
    err_location(cpp_name.location());
    str << "constructors cannot be virtual";
    throw 0;
  }

  if(!is_constructor && is_explicit)
  {
    err_location(cpp_name.location());
    str << "only constructors can be explicit";
    throw 0;
  }

  if(is_constructor &&
     base_name!=id2string(symbol.base_name))
  {
    err_location(cpp_name.location());
    str << "member function must return a value or void";
    throw 0;
  }

  if(is_destructor &&
     base_name!="~"+id2string(symbol.base_name))
  {
    err_location(cpp_name.location());
    str << "destructor with wrong name";
    throw 0;
  }

  // now do actual work

  struct_typet::componentt component;

  irep_idt identifier=
    language_prefix+
    cpp_scopes.current_scope().prefix+
    id2string(base_name);

  component.set(ID_name, identifier);
  component.type()=final_type;
  component.set(ID_access, access);
  component.set(ID_base_name, base_name);
  component.set(ID_pretty_name, base_name);
  component.location()=cpp_name.location();

  if(cpp_name.is_operator())
  {
    component.set("is_operator", true);
    component.type().set("#is_operator", true);
  }

  if(is_cast_operator)
    component.set("is_cast_operator", true);

  if(declaration.member_spec().is_explicit())
    component.set("is_explicit", true);

  typet &method_qualifier=
    (typet &)declarator.add("method_qualifier");

  if(is_static)
  {
    component.set(ID_is_static, true);
    component.type().set("#is_static", true);
  }

  if(is_typedef)
    component.set("is_type", true);

  if(is_mutable)
    component.set("is_mutable", true);

  exprt &value=declarator.value();
  irept &initializers=declarator.member_initializers();

  if(is_method)
  {
    component.set(ID_is_inline, declaration.member_spec().is_inline());

    // the 'virtual' name of the function
    std::string virtual_name=
    component.get_string(ID_base_name)+
      id2string(
        function_identifier(static_cast<const typet &>(component.find(ID_type))));

    if(method_qualifier.id()==ID_const)
      virtual_name += "$const";

    if(component.type().get(ID_return_type) == ID_destructor)
      virtual_name= "@dtor";
    
    // The method may be virtual implicitly.
    std::set<irep_idt> virtual_bases;

    for(struct_typet::componentst::const_iterator
        it=components.begin();
        it!=components.end();
        it++)
    {
      if(it->get_bool("is_virtual"))
      {
        if(it->get("virtual_name")==virtual_name)
        {
          is_virtual=true;
          const code_typet& code_type = to_code_type(it->type());
          assert(code_type.arguments().size()>0);
          const typet& pointer_type = code_type.arguments()[0].type();
          assert(pointer_type.id() == ID_pointer);
          virtual_bases.insert(pointer_type.subtype().get(ID_identifier));
        }
      }
    }

    if(!is_virtual)
    {
      typecheck_member_function(
        symbol.name, component, initializers,
        method_qualifier, value);

      if(!value.is_nil() && !is_static)
      {
        err_location(cpp_name.location());
        str << "no initialization allowed here";
        throw 0;
      }
    }
    else // virtual
    {
      component.type().set("#is_virtual", true);
      component.type().set("#virtual_name",virtual_name);

      // Check if it is a pure virtual method
      if(is_virtual)
      {
        if(value.is_not_nil() && value.id() == ID_constant)
        {
          mp_integer i;
          to_integer(value, i);
          if(i!=0)
          {
            err_location(declarator.name().location());
            str << "expected 0 to mark pure virtual method, got " << i;
          }
          component.set("is_pure_virtual", true);
          value.make_nil();
        }
      }

      typecheck_member_function(
        symbol.name,
        component,
        initializers,
        method_qualifier,
        value);

      // get the virtual-table symbol type
      irep_idt vt_name = "virtual_table::"+symbol.name.as_string();

      contextt::symbolst::iterator vtit =
        context.symbols.find(vt_name);

      if(vtit == context.symbols.end())
      {
        // first time: create a virtual-table symbol type 
        symbolt vt_symb_type;
        vt_symb_type.name= vt_name;
        vt_symb_type.base_name="virtual_table::"+symbol.base_name.as_string();
        vt_symb_type.pretty_name = vt_symb_type.base_name;
        vt_symb_type.mode=ID_cpp;
        vt_symb_type.module=module;
        vt_symb_type.location=symbol.location;
        vt_symb_type.type = struct_typet();
        vt_symb_type.type.set(ID_name, vt_symb_type.name);
        vt_symb_type.is_type = true;

        bool failed = context.move(vt_symb_type);
        assert(!failed);
        vtit = context.symbols.find(vt_name);

        // add a virtual-table pointer 
        struct_typet::componentt compo;
        compo.type() = pointer_typet(symbol_typet(vt_name));
        compo.set_name(symbol.name.as_string() +"::@vtable_pointer");
        compo.set(ID_base_name, "@vtable_pointer");
        compo.set(ID_pretty_name, symbol.base_name.as_string() +"@vtable_pointer");
        compo.set("is_vtptr", true);
        compo.set(ID_access, ID_public);
        components.push_back(compo);
        put_compound_into_scope(compo);
      }
      
      assert(vtit->second.type.id()==ID_struct);

      struct_typet &virtual_table=
        to_struct_type(vtit->second.type);

      component.set("virtual_name", virtual_name);
      component.set("is_virtual", is_virtual);

      // add an entry to the virtual table
      struct_typet::componentt vt_entry;
      vt_entry.type() = pointer_typet(component.type());
      vt_entry.set_name(vtit->first.as_string()+"::"+virtual_name);
      vt_entry.set(ID_base_name, virtual_name);
      vt_entry.set(ID_pretty_name, virtual_name);
      vt_entry.set(ID_access, ID_public);
      vt_entry.location() = symbol.location;
      virtual_table.components().push_back(vt_entry);

      // take care of overloading
      while(!virtual_bases.empty())
      {
        irep_idt virtual_base = *virtual_bases.begin();

        // a new function that does 'late casting' of the 'this' parameter
        symbolt func_symb;
        func_symb.name=component.get_name().as_string() + "::" +virtual_base.as_string();
        func_symb.base_name=component.get(ID_base_name);
        func_symb.pretty_name = component.get(ID_base_name);
        func_symb.mode=ID_cpp;
        func_symb.module=module;
        func_symb.location=component.location();
        func_symb.type=component.type();

        // change the type of the 'this' pointer
        code_typet& code_type = to_code_type(func_symb.type);
        code_typet::argumentt& arg= code_type.arguments().front();
        arg.type().subtype().set(ID_identifier, virtual_base);

        // create symbols for the arguments
        code_typet::argumentst& args =  code_type.arguments();
        for(unsigned i=0; i<args.size(); i++)
        {
          code_typet::argumentt& arg = args[i];
          irep_idt base_name = arg.get_base_name();

          if(base_name==irep_idt())
            base_name="arg"+i2string(i);

          symbolt arg_symb;
          arg_symb.name = func_symb.name.as_string() + "::"+ base_name.as_string();
          arg_symb.base_name = base_name;
          arg_symb.pretty_name = base_name;
          arg_symb.mode=ID_cpp;
          arg_symb.location=func_symb.location;
          arg_symb.type = arg.type();

          arg.set(ID_C_identifier, arg_symb.name);

          // add the argument to the symbol table
          bool failed = context.move(arg_symb);
          assert(!failed);
        }

        // do the body of the function
        typecast_exprt late_cast(to_code_type(component.type()).arguments()[0].type());

        late_cast.op0()=
          symbol_expr(namespacet(context).lookup(
            args[0].get(ID_C_identifier)));
        
        if(code_type.return_type().id()!=ID_empty &&
           code_type.return_type().id()!=ID_destructor)
        {
          side_effect_expr_function_callt expr_call;
          expr_call.function() = symbol_exprt(component.get_name(),component.type());
          expr_call.type() = to_code_type(component.type()).return_type();
          expr_call.arguments().reserve(args.size());
          expr_call.arguments().push_back(late_cast);

          for(unsigned i=1; i < args.size(); i++)
          {
            expr_call.arguments().push_back(
              symbol_expr(namespacet(context).lookup(
                args[i].get(ID_C_identifier))));
          }

          code_returnt code_return;
          code_return.return_value() = expr_call;

          func_symb.value = code_return;
        }
        else
        {
          code_function_callt code_func;
          code_func.function() = symbol_exprt(component.get_name(),component.type());
          code_func.arguments().reserve(args.size());
          code_func.arguments().push_back(late_cast);

          for(unsigned i=1; i < args.size(); i++)
          {
            code_func.arguments().push_back(
              symbol_expr(namespacet(context).lookup(
                args[i].get(ID_C_identifier))));
          }

          func_symb.value = code_func;
        }

        // add this new function to the list of components
        
        struct_typet::componentt new_compo = component;
        new_compo.type() = func_symb.type;
        new_compo.set_name(func_symb.name);
        components.push_back(new_compo);

        // add the function to the symbol table
        {
          bool failed = context.move(func_symb);
          assert(!failed);
        }

        // next base
        virtual_bases.erase(virtual_bases.begin());
      }
    }
  }
  
  if(is_static && !is_method) // static non-method member
  {
    // add as global variable to context
    symbolt static_symbol;
    static_symbol.mode=symbol.mode;
    static_symbol.name=identifier;
    static_symbol.type=component.type();
    static_symbol.base_name=component.get(ID_base_name);
    static_symbol.lvalue=true;
    static_symbol.static_lifetime=true;
    static_symbol.location=cpp_name.location();
    static_symbol.is_extern=true;
    
    // TODO: not sure about this: should be defined separately!
    dynamic_initializations.push_back(static_symbol.name);

    symbolt *new_symbol;
    if(context.move(static_symbol, new_symbol))
    {
      err_location(cpp_name.location());
	str << "redeclaration of static member `" 
	    << static_symbol.base_name.as_string()
	    << "'";
      throw 0;
    }

    if(value.is_not_nil())
    {
      if(cpp_is_pod(new_symbol->type))
      {
        new_symbol->value.swap(value);
        c_typecheck_baset::do_initializer(*new_symbol);

        // these are macros if they are PODs and come with a (constant) value
        if(new_symbol->type.get_bool(ID_C_constant))
        {
          simplify(new_symbol->value, *this);
          new_symbol->is_macro=true;
        }
      }
      else
      {
        symbol_exprt symexpr;
        symexpr.set_identifier(new_symbol->name);

        exprt::operandst ops;
        ops.push_back(value);
        codet defcode =
          cpp_constructor(locationt(), symexpr, ops);

        new_symbol->value.swap(defcode);
      }
    }
  }

  // array members must have fixed size
  check_fixed_size_array(component.type());

  put_compound_into_scope(component);

  components.push_back(component);
}