Exemple #1
0
void goto_convertt::convert_msc_leave(
  const codet &code,
  goto_programt &dest)
{
  if(!targets.leave_set)
  {
    error().source_location=code.find_source_location();
    error() << "leave without target" << eom;
    throw 0;
  }
  
  // need to process destructor stack
  for(unsigned d=targets.destructor_stack.size();
      d!=targets.leave_stack_size;
      d--)
  {
    codet d_code=targets.destructor_stack[d-1];
    d_code.add_source_location()=code.source_location();
    convert(d_code, dest);
  }

  goto_programt::targett t=dest.add_instruction();
  t->make_goto(targets.leave_target);
  t->source_location=code.source_location();
}
Exemple #2
0
void goto_convertt::convert_CPROVER_throw(
  const codet &code,
  goto_programt &dest)
{
  // set the 'exception' flag
  {
    goto_programt::targett t_set_exception=
      dest.add_instruction(ASSIGN);

    t_set_exception->source_location=code.source_location();
    t_set_exception->code=code_assignt(exception_flag(), true_exprt());
  }

  // do we catch locally?
  if(targets.throw_set)
  {
    // need to process destructor stack
    unwind_destructor_stack(code.source_location(), targets.throw_stack_size, dest);

    // add goto
    goto_programt::targett t=dest.add_instruction();
    t->make_goto(targets.throw_target);
    t->source_location=code.source_location();
  }
  else // otherwise, we do a return
  {
    // need to process destructor stack
    unwind_destructor_stack(code.source_location(), 0, dest);

    // add goto
    goto_programt::targett t=dest.add_instruction();
    t->make_goto(targets.return_target);
    t->source_location=code.source_location();
  }
}
void goto_convertt::convert_CPROVER_try_catch(
  const codet &code,
  goto_programt &dest)
{
  if(code.operands().size()!=2)
  {
    err_location(code);
    throw "CPROVER_try_catch expects two arguments";
  }

  // this is where we go after 'throw'
  goto_programt tmp;
  tmp.add_instruction(SKIP)->source_location=code.source_location();

  // set 'throw' target
  throw_targett throw_target(targets);
  targets.set_throw(tmp.instructions.begin());
  
  // now put 'catch' code onto destructor stack
  code_ifthenelset catch_code;
  catch_code.cond()=exception_flag();
  catch_code.add_source_location()=code.source_location();
  catch_code.then_case()=to_code(code.op1());

  targets.destructor_stack.push_back(catch_code);

  // now convert 'try' code
  convert(to_code(code.op0()), dest);

  // pop 'catch' code off stack
  targets.destructor_stack.pop_back();
  
  // add 'throw' target
  dest.destructive_append(tmp);
}
void goto_convertt::convert_java_try_catch(
  const codet &code,
  goto_programt &dest)
{
  assert(!code.operands().empty());

  // add the CATCH instruction to 'dest'
  goto_programt::targett catch_instruction=dest.add_instruction();
  catch_instruction->make_catch();
  catch_instruction->code.set_statement(ID_catch);
  catch_instruction->source_location=code.source_location();
  catch_instruction->function=code.source_location().get_function();

  // the CATCH instruction is annotated with a list of exception IDs
  const irept exceptions=code.op0().find(ID_exception_list);
  if(exceptions.is_not_nil())
  {
    irept::subt exceptions_sub=exceptions.get_sub();
    irept::subt &exception_list=
      catch_instruction->code.add(ID_exception_list).get_sub();
    exception_list.resize(exceptions_sub.size());
    for(size_t i=0; i<exceptions_sub.size(); ++i)
      exception_list[i].id(exceptions_sub[i].id());
  }

  // the CATCH instruction is also annotated with a list of handle labels
  const irept handlers=code.op0().find(ID_label);
  if(handlers.is_not_nil())
  {
    irept::subt handlers_sub=handlers.get_sub();
    irept::subt &handlers_list=
      catch_instruction->code.add(ID_label).get_sub();
    handlers_list.resize(handlers_sub.size());
    for(size_t i=0; i<handlers_sub.size(); ++i)
      handlers_list[i].id(handlers_sub[i].id());
  }

  // the CATCH instruction may also signal a handler
  if(code.op0().has_operands())
  {
    catch_instruction->code.get_sub().resize(1);
    catch_instruction->code.get_sub()[0]=code.op0().op0();
  }

  // add a SKIP target for the end of everything
  goto_programt end;
  goto_programt::targett end_target=end.add_instruction();
  end_target->make_skip();
  end_target->source_location=code.source_location();
  end_target->function=code.source_location().get_function();

  // add the end-target
  dest.destructive_append(end);
}
Exemple #5
0
void c_typecheck_baset::typecheck_return(codet &code)
{
  if(code.operands().empty())
  {
    if(follow(return_type).id()!=ID_empty)
    {
      // gcc doesn't actually complain, it just warns!
      // We'll put a zero here, which is dubious.
      exprt zero=zero_initializer(return_type, code.source_location(), *this, get_message_handler());
      code.copy_to_operands(zero);
    }
  }
  else if(code.operands().size()==1)
  {
    typecheck_expr(code.op0());

    if(follow(return_type).id()==ID_empty)
    {
      // gcc doesn't actually complain, it just warns!
      if(follow(code.op0().type()).id()!=ID_empty)
      {
        warning().source_location=code.source_location();

        warning() << "function has return void ";
        warning() << "but a return statement returning ";
        warning() << to_string(follow(code.op0().type()));
        warning() << eom;

        code.op0().make_typecast(return_type);
      }
    }
    else
      implicit_typecast(code.op0(), return_type);
  }
  else
  {
    err_location(code);
    error() << "return expected to have 0 or 1 operands" << eom;
    throw 0;
  }
}
Exemple #6
0
void goto_convertt::convert_try_catch(
  const codet &code,
  goto_programt &dest)
{
  assert(code.operands().size()>=2);
  
  // add the CATCH-push instruction to 'dest'
  goto_programt::targett catch_push_instruction=dest.add_instruction();
  catch_push_instruction->make_catch();
  catch_push_instruction->code.set_statement(ID_catch);
  catch_push_instruction->source_location=code.source_location();
  
  // the CATCH-push instruction is annotated with a list of IDs,
  // one per target
  irept::subt &exception_list=
    catch_push_instruction->code.add(ID_exception_list).get_sub();

  // add a SKIP target for the end of everything
  goto_programt end;
  goto_programt::targett end_target=end.add_instruction();
  end_target->make_skip();
  
  // the first operand is the 'try' block
  convert(to_code(code.op0()), dest);
  
  // add the CATCH-pop to the end of the 'try' block
  goto_programt::targett catch_pop_instruction=dest.add_instruction();
  catch_pop_instruction->make_catch();
  catch_pop_instruction->code.set_statement(ID_catch);
  
  // add a goto to the end of the 'try' block
  dest.add_instruction()->make_goto(end_target);

  for(unsigned i=1; i<code.operands().size(); i++)
  {
    const codet &block=to_code(code.operands()[i]);
  
    // grab the ID and add to CATCH instruction
    exception_list.push_back(irept(block.get(ID_exception_id)));
    
    goto_programt tmp;
    convert(block, tmp);
    catch_push_instruction->targets.push_back(tmp.instructions.begin());
    dest.destructive_append(tmp);

    // add a goto to the end of the 'catch' block
    dest.add_instruction()->make_goto(end_target);
  }

  // add the end-target  
  dest.destructive_append(end);
}
Exemple #7
0
void goto_convertt::convert_msc_try_finally(
  const codet &code,
  goto_programt &dest)
{
  if(code.operands().size()!=2)
  {
    error().source_location=code.find_source_location();
    error() << "msc_try_finally expects two arguments" << eom;
    throw 0;
  }
  
  goto_programt tmp;
  tmp.add_instruction(SKIP)->source_location=code.source_location();

  {  
    // save 'leave' target
    leave_targett leave_target(targets);
    targets.set_leave(tmp.instructions.begin());
    
    // first put 'finally' code onto destructor stack
    targets.destructor_stack.push_back(to_code(code.op1()));
  
    // do 'try' code
    convert(to_code(code.op0()), dest);

    // pop 'finally' from destructor stack
    targets.destructor_stack.pop_back();
    
    // 'leave' target gets restored here
  }

  // now add 'finally' code
  convert(to_code(code.op1()), dest);
  
  // this is the target for 'leave'
  dest.destructive_append(tmp);
}
Exemple #8
0
void c_typecheck_baset::typecheck_for(codet &code)
{
  if(code.operands().size()!=4)
  {
    err_location(code);
    error() << "for expected to have four operands" << eom;
    throw 0;
  }

  // the "for" statement has an implicit block around it,
  // since code.op0() may contain declarations
  //
  // we therefore transform
  //
  //   for(a;b;c) d;
  //
  // to
  //
  //   { a; for(;b;c) d; }
  //
  // if config.ansi_c.for_has_scope

  if(!config.ansi_c.for_has_scope ||
     code.op0().is_nil())
  {
    if(code.op0().is_not_nil())
      typecheck_code(to_code(code.op0()));

    if(code.op1().is_nil())
      code.op1()=true_exprt();
    else
    {
      typecheck_expr(code.op1());
      implicit_typecast_bool(code.op1());
    }

    if(code.op2().is_not_nil())
      typecheck_expr(code.op2());

    if(code.op3().is_not_nil())
    {
      // save & set flags
      bool old_break_is_allowed=break_is_allowed;
      bool old_continue_is_allowed=continue_is_allowed;

      break_is_allowed=continue_is_allowed=true;

      // recursive call
      if(to_code(code.op3()).get_statement()==ID_decl_block)
      {
        code_blockt code_block;
        code_block.add_source_location()=code.op3().source_location();

        code_block.move_to_operands(code.op3());
        code.op3().swap(code_block);
      }
      typecheck_code(to_code(code.op3()));

      // restore flags
      break_is_allowed=old_break_is_allowed;
      continue_is_allowed=old_continue_is_allowed;
    }
  }
  else
  {
    code_blockt code_block;
    code_block.add_source_location()=code.source_location();
    if(to_code(code.op3()).get_statement()==ID_block)
      code_block.set(
        ID_C_end_location,
        to_code_block(to_code(code.op3())).end_location());
    else
      code_block.set(
        ID_C_end_location,
        code.op3().source_location());;

    code_block.reserve_operands(2);
    code_block.move_to_operands(code.op0());
    code.op0().make_nil();
    code_block.move_to_operands(code);
    code.swap(code_block);
    typecheck_code(code); // recursive call
  }

  typecheck_spec_expr(code, ID_C_spec_loop_invariant);
}
Exemple #9
0
void c_typecheck_baset::typecheck_decl(codet &code)
{
  // this comes with 1 operand, which is a declaration
  if(code.operands().size()!=1)
  {
    err_location(code);
    error() << "decl expected to have 1 operand" << eom;
    throw 0;
  }

  // op0 must be declaration
  if(code.op0().id()!=ID_declaration)
  {
    err_location(code);
    error() << "decl statement expected to have declaration as operand"
            << eom;
    throw 0;
  }

  ansi_c_declarationt declaration;
  declaration.swap(code.op0());

  if(declaration.get_is_static_assert())
  {
    assert(declaration.operands().size()==2);
    codet new_code(ID_static_assert);
    new_code.add_source_location()=code.source_location();
    new_code.operands().swap(declaration.operands());
    code.swap(new_code);
    typecheck_code(code);
    return; // done
  }

  typecheck_declaration(declaration);

  std::list<codet> new_code;

  // iterate over declarators

  for(ansi_c_declarationt::declaratorst::const_iterator
      d_it=declaration.declarators().begin();
      d_it!=declaration.declarators().end();
      d_it++)
  {
    irep_idt identifier=d_it->get_name();

    // look it up
    symbol_tablet::symbolst::iterator s_it=
      symbol_table.symbols.find(identifier);

    if(s_it==symbol_table.symbols.end())
    {
      err_location(code);
      error() << "failed to find decl symbol `" << identifier
              << "' in symbol table" << eom;
      throw 0;
    }

    symbolt &symbol=s_it->second;

    // This must not be an incomplete type, unless it's 'extern'
    // or a typedef.
    if(!symbol.is_type &&
       !symbol.is_extern &&
       !is_complete_type(symbol.type))
    {
      error().source_location=symbol.location;
      error() << "incomplete type not permitted here" << eom;
      throw 0;
    }

    // see if it's a typedef
    // or a function
    // or static
    if(symbol.is_type ||
       symbol.type.id()==ID_code ||
       symbol.is_static_lifetime)
    {
      // we ignore
    }
    else
    {
      code_declt code;
      code.add_source_location()=symbol.location;
      code.symbol()=symbol.symbol_expr();
      code.symbol().add_source_location()=symbol.location;

      // add initializer, if any
      if(symbol.value.is_not_nil())
      {
        code.operands().resize(2);
        code.op1()=symbol.value;
      }

      new_code.push_back(code);
    }
  }

  // stash away any side-effects in the declaration
  new_code.splice(new_code.begin(), clean_code);

  if(new_code.empty())
  {
    source_locationt source_location=code.source_location();
    code=code_skipt();
    code.add_source_location()=source_location;
  }
  else if(new_code.size()==1)
  {
    code.swap(new_code.front());
  }
  else
  {
    // build a decl-block
    code_blockt code_block(new_code);
    code_block.set_statement(ID_decl_block);
    code.swap(code_block);
  }
}