Exemplo n.º 1
0
void c_typecheck_baset::typecheck_declaration(
  ansi_c_declarationt &declaration)
{
  if(declaration.get_is_static_assert())
  {
    assert(declaration.operands().size()==2);
    typecheck_expr(declaration.op0());
    typecheck_expr(declaration.op1());
  }
  else
  {
    // get storage spec
    c_storage_spect c_storage_spec(declaration.type());
  
    declaration.set_is_inline(c_storage_spec.is_inline);
    declaration.set_is_static(c_storage_spec.is_static);
    declaration.set_is_extern(c_storage_spec.is_extern);
    declaration.set_is_thread_local(c_storage_spec.is_thread_local);
    declaration.set_is_register(c_storage_spec.is_register);
    declaration.set_is_typedef(c_storage_spec.is_typedef);

    // first typecheck the type of the declaration
    typecheck_type(declaration.type());
    
    // mark as 'already typechecked'
    make_already_typechecked(declaration.type());

    // Now do declarators, if any.
    for(ansi_c_declarationt::declaratorst::iterator
        d_it=declaration.declarators().begin();
        d_it!=declaration.declarators().end();
        d_it++)
    {
      symbolt symbol;
      declaration.to_symbol(*d_it, symbol);

      // now check other half of type
      typecheck_type(symbol.type);

      typecheck_symbol(symbol);
    }
  }
}
Exemplo n.º 2
0
void c_typecheck_baset::typecheck_compound_body(
  struct_union_typet &type)
{
  struct_union_typet::componentst &components=type.components();

  struct_union_typet::componentst old_components;
  old_components.swap(components);

  // We get these as declarations!
  for(auto &decl : old_components)
  {
    // the arguments are member declarations or static assertions
    assert(decl.id()==ID_declaration);

    ansi_c_declarationt &declaration=
      to_ansi_c_declaration(static_cast<exprt &>(decl));

    if(declaration.get_is_static_assert())
    {
      struct_union_typet::componentt new_component;
      new_component.id(ID_static_assert);
      new_component.add_source_location()=declaration.source_location();
      new_component.operands().swap(declaration.operands());
      assert(new_component.operands().size()==2);
      components.push_back(new_component);
    }
    else
    {
      // do first half of type
      typecheck_type(declaration.type());
      make_already_typechecked(declaration.type());

      for(const auto &declarator : declaration.declarators())
      {
        struct_union_typet::componentt new_component;

        new_component.add_source_location()=
          declarator.source_location();
        new_component.set(ID_name, declarator.get_base_name());
        new_component.set(ID_pretty_name, declarator.get_base_name());
        new_component.type()=declaration.full_type(declarator);

        typecheck_type(new_component.type());

        if(!is_complete_type(new_component.type()) &&
           (new_component.type().id()!=ID_array ||
            !to_array_type(new_component.type()).is_incomplete()))
        {
          error().source_location=new_component.type().source_location();
          error() << "incomplete type not permitted here" << eom;
          throw 0;
        }

        components.push_back(new_component);
      }
    }
  }

  unsigned anon_member_counter=0;

  // scan for anonymous members, and name them
  for(auto &member : components)
  {
    if(member.get_name()!=irep_idt())
      continue;

    member.set_name("$anon"+std::to_string(anon_member_counter++));
    member.set_anonymous(true);
  }

  // scan for duplicate members

  {
    std::unordered_set<irep_idt, irep_id_hash> members;

    for(struct_union_typet::componentst::iterator
        it=components.begin();
        it!=components.end();
        it++)
    {
      if(!members.insert(it->get_name()).second)
      {
        error().source_location=it->source_location();
        error() << "duplicate member '" << it->get_name() << '\'' << eom;
        throw 0;
      }
    }
  }

  // We allow an incomplete (C99) array as _last_ member!
  // Zero-length is allowed everywhere.

  if(type.id()==ID_struct ||
     type.id()==ID_union)
  {
    for(struct_union_typet::componentst::iterator
        it=components.begin();
        it!=components.end();
        it++)
    {
      typet &c_type=it->type();

      if(c_type.id()==ID_array &&
         to_array_type(c_type).is_incomplete())
      {
        // needs to be last member
        if(type.id()==ID_struct && it!=--components.end())
        {
          error().source_location=it->source_location();
          error() << "flexible struct member must be last member" << eom;
          throw 0;
        }

        // make it zero-length
        c_type.id(ID_array);
        c_type.set(ID_size, from_integer(0, index_type()));
      }
    }
  }

  // We may add some minimal padding inside and at
  // the end of structs and
  // as additional member for unions.

  if(type.id()==ID_struct)
    add_padding(to_struct_type(type), *this);
  else if(type.id()==ID_union)
    add_padding(to_union_type(type), *this);

  // Now remove zero-width bit-fields, these are just
  // for adjusting alignment.
  for(struct_typet::componentst::iterator
      it=components.begin();
      it!=components.end();
      ) // blank
  {
    if(it->type().id()==ID_c_bit_field &&
       to_c_bit_field_type(it->type()).get_width()==0)
      it=components.erase(it);
    else
      it++;
  }

  // finally, check _Static_assert inside the compound
  for(struct_union_typet::componentst::iterator
      it=components.begin();
      it!=components.end();
      ) // no it++
  {
    if(it->id()==ID_static_assert)
    {
      assert(it->operands().size()==2);
      exprt &assertion=it->op0();
      typecheck_expr(assertion);
      typecheck_expr(it->op1());
      assertion.make_typecast(bool_typet());
      make_constant(assertion);

      if(assertion.is_false())
      {
        error().source_location=it->source_location();
        error() << "failed _Static_assert" << eom;
        throw 0;
      }
      else if(!assertion.is_true())
      {
        // should warn/complain
      }

      it=components.erase(it);
    }
    else
      it++;
  }
}
Exemplo n.º 3
0
void c_typecheck_baset::typecheck_declaration(
  ansi_c_declarationt &declaration)
{
  if(declaration.get_is_static_assert())
  {
    assert(declaration.operands().size()==2);
    typecheck_expr(declaration.op0());
    typecheck_expr(declaration.op1());
  }
  else
  {
    // get storage spec
    c_storage_spect c_storage_spec(declaration.type());

    // first typecheck the type of the declaration
    typecheck_type(declaration.type());

    // mark as 'already typechecked'
    make_already_typechecked(declaration.type());

    codet contract;

    {
      exprt spec_requires=
        static_cast<const exprt&>(declaration.find(ID_C_spec_requires));
      contract.add(ID_C_spec_requires).swap(spec_requires);

      exprt spec_ensures=
        static_cast<const exprt&>(declaration.find(ID_C_spec_ensures));
      contract.add(ID_C_spec_ensures).swap(spec_ensures);
    }

    // Now do declarators, if any.
    for(ansi_c_declarationt::declaratorst::iterator
        d_it=declaration.declarators().begin();
        d_it!=declaration.declarators().end();
        d_it++)
    {
      c_storage_spect full_spec(declaration.full_type(*d_it));
      full_spec|=c_storage_spec;

      declaration.set_is_inline(full_spec.is_inline);
      declaration.set_is_static(full_spec.is_static);
      declaration.set_is_extern(full_spec.is_extern);
      declaration.set_is_thread_local(full_spec.is_thread_local);
      declaration.set_is_register(full_spec.is_register);
      declaration.set_is_typedef(full_spec.is_typedef);
      declaration.set_is_weak(full_spec.is_weak);

      symbolt symbol;
      declaration.to_symbol(*d_it, symbol);
      current_symbol=symbol;

      // now check other half of type
      typecheck_type(symbol.type);

      if(!full_spec.alias.empty())
      {
        if(symbol.value.is_not_nil())
        {
          error().source_location=symbol.location;
          error() << "alias attribute cannot be used with a body"
                  << eom;
          throw 0;
        }

        // alias function need not have been declared yet, thus
        // can't lookup
        symbol.value=symbol_exprt(full_spec.alias);
        symbol.is_macro=true;
      }

      if(full_spec.section.empty())
        apply_asm_label(full_spec.asm_label, symbol);
      else
      {
        std::string asm_name;
        asm_name=id2string(full_spec.section)+"$$";
        if(!full_spec.asm_label.empty())
          asm_name+=id2string(full_spec.asm_label);
        else
          asm_name+=id2string(symbol.name);

        apply_asm_label(asm_name, symbol);
      }
      irep_idt identifier=symbol.name;
      d_it->set_name(identifier);

      typecheck_symbol(symbol);

      // add code contract (if any); we typecheck this after the
      // function body done above, so as to have parameter symbols
      // available
      symbol_tablet::symbolst::iterator s_it=
        symbol_table.symbols.find(identifier);
      assert(s_it!=symbol_table.symbols.end());
      symbolt &new_symbol=s_it->second;

      typecheck_spec_expr(contract, ID_C_spec_requires);

      typet ret_type=empty_typet();
      if(new_symbol.type.id()==ID_code)
        ret_type=to_code_type(new_symbol.type).return_type();
      assert(parameter_map.empty());
      if(ret_type.id()!=ID_empty)
        parameter_map["__CPROVER_return_value"]=ret_type;
      typecheck_spec_expr(contract, ID_C_spec_ensures);
      parameter_map.clear();

      if(contract.find(ID_C_spec_requires).is_not_nil())
        new_symbol.type.add(ID_C_spec_requires)=
          contract.find(ID_C_spec_requires);
      if(contract.find(ID_C_spec_ensures).is_not_nil())
        new_symbol.type.add(ID_C_spec_ensures)=
          contract.find(ID_C_spec_ensures);
    }
  }
}