Exemple #1
0
void cpp_typecheckt::static_initialization()
{
  code_blockt block_sini; // Static Initialization Block
  code_blockt block_dini; // Dynamic Initialization Block

  disable_access_control = true;

  // first do zero initialization
  context.foreach_operand([this, &block_sini](const symbolt &s) {
    if(!s.static_lifetime || s.mode != current_mode)
      return;

    // it has a non-code initializer already?
    if(s.value.is_not_nil() && s.value.id() != "code")
      return;

    // it's a declaration only
    if(s.is_extern)
      return;

    if(!s.lvalue)
      return;

    zero_initializer(
      cpp_symbol_expr(s), s.type, s.location, block_sini.operands());
  });

  while(!dinis.empty())
  {
    symbolt &symbol = *context.find_symbol(dinis.front());
    dinis.pop_front();

    if(symbol.is_extern)
      continue;

    if(symbol.mode != current_mode)
      continue;

    assert(symbol.static_lifetime);
    assert(!symbol.is_type);
    assert(symbol.type.id() != "code");

    exprt symexpr = cpp_symbol_expr(symbol);

    if(symbol.value.is_not_nil())
    {
      if(!cpp_is_pod(symbol.type))
      {
        block_dini.move_to_operands(symbol.value);
      }
      else
      {
        exprt symbexpr("symbol", symbol.type);
        symbexpr.identifier(symbol.name);

        codet code;
        code.set_statement("assign");
        code.copy_to_operands(symbexpr, symbol.value);
        code.location() = symbol.location;

        if(symbol.value.id() == "constant")
          block_sini.move_to_operands(code);
        else
          block_dini.move_to_operands(code);
      }

      // Make it nil because we do not want
      // global_init to try to initialize the
      // object
      symbol.value.make_nil();
    }
    else
    {
      exprt::operandst ops;

      codet call = cpp_constructor(locationt(), symexpr, ops);

      if(call.is_not_nil())
        block_dini.move_to_operands(call);
    }
  }

  block_sini.move_to_operands(block_dini);

  // Create the initialization procedure
  symbolt init_symbol;

  init_symbol.name = "#ini#" + id2string(module);
  init_symbol.base_name = "#ini#" + id2string(module);
  init_symbol.value.swap(block_sini);
  init_symbol.mode = current_mode;
  init_symbol.module = module;
  init_symbol.type = code_typet();
  init_symbol.type.add("return_type") = typet("empty");
  init_symbol.type.set("initialization", true);
  init_symbol.is_type = false;
  init_symbol.is_macro = false;

  context.move(init_symbol);

  disable_access_control = false;
}
Exemple #2
0
bool cpp_typecheckt::cpp_is_pod(const typet &type) const
{
  if(type.id()==ID_struct)
  {
    // Not allowed in PODs:
    // * Non-PODs
    // * Constructors/Destructors
    // * virtuals
    // * private/protected, unless static
    // * overloading assignment operator
    // * Base classes

    const struct_typet &struct_type=to_struct_type(type);

    if(!type.find(ID_bases).get_sub().empty())
      return false;

    const struct_typet::componentst &components=
      struct_type.components();

    for(struct_typet::componentst::const_iterator
        it=components.begin();
        it!=components.end();
        it++)
    {
      if(it->get_bool(ID_is_type))
        continue;

      if(it->get_base_name()=="operator=")
        return false;

      if(it->get_bool(ID_is_virtual))
        return false;

      const typet &sub_type=it->type();

      if(sub_type.id()==ID_code)
      {
        if(it->get_bool(ID_is_virtual))
          return false;

        const typet &return_type=to_code_type(sub_type).return_type();

        if(return_type.id()==ID_constructor ||
           return_type.id()==ID_destructor)
          return false;
      }
      else if(it->get(ID_access)!=ID_public &&
              !it->get_bool(ID_is_static))
        return false;

      if(!cpp_is_pod(sub_type))
        return false;
    }

    return true;
  }
  else if(type.id()==ID_array)
  {
    return cpp_is_pod(type.subtype());
  }
  else if(type.id()==ID_pointer)
  {
    if(is_reference(type)) // references are not PODs
      return false;

    // but pointers are PODs!
    return true;
  }
  else if(type.id()==ID_symbol)
  {
    const symbolt &symb=lookup(type.get(ID_identifier));
    assert(symb.is_type);
    return cpp_is_pod(symb.type);
  }

  // everything else is POD
  return true;
}
Exemple #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;
}
Exemple #4
0
void cpp_typecheckt::convert_anonymous_union(
  cpp_declarationt &declaration,
  codet &code)
{
  codet new_code(ID_decl_block);
  new_code.reserve_operands(declaration.declarators().size());

  // unnamed object
  std::string identifier="#anon_union"+i2string(anon_counter++);

  irept name(ID_name);
  name.set(ID_identifier, identifier);
  name.set(ID_C_source_location, declaration.source_location());

  cpp_namet cpp_name;
  cpp_name.move_to_sub(name);
  cpp_declaratort declarator;
  declarator.name()=cpp_name;

  cpp_declarator_convertert cpp_declarator_converter(*this);

  const symbolt &symbol=
    cpp_declarator_converter.convert(declaration, declarator);

  if(!cpp_is_pod(declaration.type()))
  {
   error().source_location=follow(declaration.type()).source_location();
   error() << "anonymous union is not POD" << eom;
   throw 0;
  }

  codet decl_statement(ID_decl);
  decl_statement.reserve_operands(2);
  decl_statement.copy_to_operands(cpp_symbol_expr(symbol));

  new_code.move_to_operands(decl_statement);

  // do scoping
  symbolt union_symbol=symbol_table.symbols[follow(symbol.type).get(ID_name)];
  const irept::subt &components=union_symbol.type.add(ID_components).get_sub();

  forall_irep(it, components)
  {
    if(it->find(ID_type).id()==ID_code)
    {
      error().source_location=union_symbol.type.source_location();
      error() << "anonymous union `" << union_symbol.base_name
              << "' shall not have function members" << eom;
      throw 0;
    }

    const irep_idt &base_name=it->get(ID_base_name);

    if(cpp_scopes.current_scope().contains(base_name))
    {
      error().source_location=union_symbol.type.source_location();
      error() << "identifier `" << base_name << "' already in scope"
              << eom;
      throw 0;
    }

    cpp_idt &id=cpp_scopes.current_scope().insert(base_name);
    id.id_class = cpp_idt::SYMBOL;
    id.identifier=it->get(ID_name);
    id.class_identifier=union_symbol.name;
    id.is_member=true;
  }

  symbol_table.symbols[union_symbol.name].type.set(
    "#unnamed_object", symbol.base_name);

  code.swap(new_code);
}
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);
}