/*******************************************************************\
Module: C++ Language Type Checking
Author: Daniel Kroening, [email protected]
\*******************************************************************/
/// \file
/// C++ Language Type Checking
#include
#include
#include "cpp_template_type.h"
#include "cpp_type2name.h"
#include "cpp_typecheck.h"
void cpp_typecheckt::convert_parameter(
const irep_idt ¤t_mode,
code_typet::parametert ¶meter)
{
irep_idt base_name=id2string(parameter.get_base_name());
if(base_name.empty())
{
base_name="#anon_arg"+std::to_string(anon_counter++);
parameter.set_base_name(base_name);
}
PRECONDITION(!cpp_scopes.current_scope().prefix.empty());
irep_idt identifier=cpp_scopes.current_scope().prefix+
id2string(base_name);
parameter.set_identifier(identifier);
// the parameter may already have been set up if dealing with virtual methods
const symbolt *check_symbol;
if(!lookup(identifier, check_symbol))
return;
parameter_symbolt symbol;
symbol.name=identifier;
symbol.base_name=parameter.get_base_name();
symbol.location=parameter.source_location();
symbol.mode = current_mode;
symbol.module=module;
symbol.type=parameter.type();
symbol.is_lvalue=!is_reference(symbol.type);
INVARIANT(!symbol.base_name.empty(), "parameter has base name");
symbolt *new_symbol;
if(symbol_table.move(symbol, new_symbol))
{
error().source_location=symbol.location;
error() << "cpp_typecheckt::convert_parameter: symbol_table.move(\""
<< symbol.name << "\") failed" << eom;
throw 0;
}
// put into scope
cpp_scopes.put_into_scope(*new_symbol);
}
void cpp_typecheckt::convert_parameters(
const irep_idt ¤t_mode,
code_typet &function_type)
{
code_typet::parameterst ¶meters=
function_type.parameters();
for(code_typet::parameterst::iterator
it=parameters.begin();
it!=parameters.end();
it++)
convert_parameter(current_mode, *it);
}
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(symbol.value.id() != ID_code)
{
error().source_location = symbol.location;
error() << "function '" << symbol.name << "' is initialized with "
<< symbol.value.id() << eom;
throw 0;
}
// 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_parameters(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::parameterst ¶meters=function_type.parameters();
DATA_INVARIANT(parameters.size() >= 1, "parameters expected");
code_typet::parametert &this_parameter_expr=parameters.front();
function_scope.this_expr = symbol_exprt{
this_parameter_expr.get_identifier(), this_parameter_expr.type()};
}
else
function_scope.this_expr.make_nil();
// if it is a destructor, add the implicit code
if(to_code_type(symbol.type).return_type().id() == ID_destructor)
{
const symbolt &msymb = lookup(symbol.type.get(ID_C_member_name));
PRECONDITION(symbol.value.id() == ID_code);
PRECONDITION(symbol.value.get(ID_statement) == ID_block);
if(
!symbol.value.has_operands() ||
!to_multi_ary_expr(symbol.value).op0().has_operands() ||
to_multi_ary_expr(to_multi_ary_expr(symbol.value).op0()).op0().id() !=
ID_already_typechecked)
{
symbol.value.copy_to_operands(
dtor(msymb, to_symbol_expr(function_scope.this_expr)));
}
}
// 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 = void_type();
typecheck_code(to_code(symbol.value));
symbol.value.type()=symbol.type;
return_type = old_return_type;
deferred_typechecking.erase(symbol.name);
}
/// for function overloading
irep_idt cpp_typecheckt::function_identifier(const typet &type)
{
const code_typet &function_type=
to_code_type(template_subtype(type));
const code_typet::parameterst ¶meters=
function_type.parameters();
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::parameterst::const_iterator it=
parameters.begin();
if(it != parameters.end() && it->get_this())
{
const typet &pointer=it->type();
const typet &symbol = to_pointer_type(pointer).base_type();
if(symbol.get_bool(ID_C_constant))
result += "$const";
if(symbol.get_bool(ID_C_volatile))
result += "$volatile";
result += id2string(ID_this);
first=false;
it++;
}
// we skipped the "this", on purpose!
for(; it!=parameters.end(); it++)
{
if(first)
first=false;
else
result+=',';
typet tmp_type=it->type();
result+=cpp_type2name(it->type());
}
result+=')';
return result;
}