C++ destructors: Ensure "this" is a fully qualified name

Typechecking does not magically expand `ID_this`, and there isn't
sufficient context to use "cpp-this."

Fixes: #661
This commit is contained in:
Michael Tautschnig 2019-03-31 20:03:16 +00:00
parent e765de3312
commit 42efbd7457
4 changed files with 26 additions and 28 deletions

View File

@ -1,6 +1,6 @@
KNOWNBUG CORE
main.cpp main.cpp
--unwind 1 --unwinding-assertions
^EXIT=0$ ^EXIT=0$
^SIGNAL=0$ ^SIGNAL=0$
^VERIFICATION SUCCESSFUL$ ^VERIFICATION SUCCESSFUL$

View File

@ -257,7 +257,7 @@ protected:
void default_dtor(const symbolt &symb, cpp_declarationt &dtor); void default_dtor(const symbolt &symb, cpp_declarationt &dtor);
codet dtor(const symbolt &symb); codet dtor(const symbolt &symb, const symbol_exprt &this_expr);
void check_member_initializers( void check_member_initializers(
const struct_typet::basest &bases, const struct_typet::basest &bases,

View File

@ -47,7 +47,7 @@ void cpp_typecheckt::default_dtor(
} }
/// produces destructor code for a class object /// produces destructor code for a class object
codet cpp_typecheckt::dtor(const symbolt &symbol) codet cpp_typecheckt::dtor(const symbolt &symbol, const symbol_exprt &this_expr)
{ {
assert(symbol.type.id()==ID_struct || assert(symbol.type.id()==ID_struct ||
symbol.type.id()==ID_union); symbol.type.id()==ID_union);
@ -85,7 +85,7 @@ codet cpp_typecheckt::dtor(const symbolt &symbol)
exprt ptrmember(ID_ptrmember); exprt ptrmember(ID_ptrmember);
ptrmember.set(ID_component_name, c.get_name()); ptrmember.set(ID_component_name, c.get_name());
ptrmember.operands().push_back(exprt("cpp-this")); ptrmember.operands().push_back(this_expr);
code_assignt assign(ptrmember, address); code_assignt assign(ptrmember, address);
block.add(assign); block.add(assign);
@ -113,8 +113,7 @@ codet cpp_typecheckt::dtor(const symbolt &symbol)
exprt member(ID_ptrmember, type); exprt member(ID_ptrmember, type);
member.set(ID_component_cpp_name, cppname); member.set(ID_component_cpp_name, cppname);
member.operands().push_back( member.operands().push_back(this_expr);
symbol_exprt(ID_this, pointer_type(symbol.type)));
member.add_source_location() = source_location; member.add_source_location() = source_location;
const bool disabled_access_control = disable_access_control; const bool disabled_access_control = disable_access_control;
@ -139,8 +138,7 @@ codet cpp_typecheckt::dtor(const symbolt &symbol)
DATA_INVARIANT(bit->id() == ID_base, "base class expression expected"); DATA_INVARIANT(bit->id() == ID_base, "base class expression expected");
const symbolt &psymb = lookup(bit->type()); const symbolt &psymb = lookup(bit->type());
symbol_exprt this_ptr(ID_this, pointer_type(symbol.type)); dereference_exprt object{this_expr, psymb.type};
dereference_exprt object(this_ptr, psymb.type);
object.add_source_location() = source_location; object.add_source_location() = source_location;
const bool disabled_access_control = disable_access_control; const bool disabled_access_control = disable_access_control;

View File

@ -90,22 +90,6 @@ void cpp_typecheckt::convert_function(symbolt &symbol)
if(symbol.value.is_nil()) if(symbol.value.is_nil())
return; return;
// 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));
assert(symbol.value.id()==ID_code);
assert(symbol.value.get(ID_statement)==ID_block);
if(
!symbol.value.has_operands() || !symbol.value.op0().has_operands() ||
symbol.value.op0().op0().id() != ID_already_typechecked)
{
symbol.value.copy_to_operands(dtor(msymb));
}
}
// enter appropriate scope // enter appropriate scope
cpp_save_scopet saved_scope(cpp_scopes); cpp_save_scopet saved_scope(cpp_scopes);
cpp_scopet &function_scope=cpp_scopes.set_scope(symbol.name); cpp_scopet &function_scope=cpp_scopes.set_scope(symbol.name);
@ -123,13 +107,29 @@ void cpp_typecheckt::convert_function(symbolt &symbol)
code_typet::parameterst &parameters=function_type.parameters(); code_typet::parameterst &parameters=function_type.parameters();
assert(parameters.size()>=1); assert(parameters.size()>=1);
code_typet::parametert &this_parameter_expr=parameters.front(); code_typet::parametert &this_parameter_expr=parameters.front();
function_scope.this_expr=exprt(ID_symbol, this_parameter_expr.type()); function_scope.this_expr = symbol_exprt{
function_scope.this_expr.set( this_parameter_expr.get_identifier(), this_parameter_expr.type()};
ID_identifier, this_parameter_expr.get_identifier());
} }
else else
function_scope.this_expr.make_nil(); 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() || !symbol.value.op0().has_operands() ||
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 // do the function body
start_typecheck_code(); start_typecheck_code();