Skip to content

Commit 4bf05c8

Browse files
authored
Merge pull request #4471 from tautschnig/c++-temporary-and-destructor
C++ destructors: Ensure "this" is a fully qualified name
2 parents e765de3 + b18138c commit 4bf05c8

13 files changed

+58
-57
lines changed

regression/cbmc-cpp/cpp1/test.desc

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
KNOWNBUG
1+
CORE
22
main.cpp
3-
3+
--unwind 1 --unwinding-assertions
44
^EXIT=0$
55
^SIGNAL=0$
66
^VERIFICATION SUCCESSFUL$

src/cpp/cpp_declarator_converter.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,15 @@ symbolt &cpp_declarator_convertert::convert(
104104
{
105105
// adjust type if it's a non-static member function
106106
if(final_type.id()==ID_code)
107+
{
108+
cpp_save_scopet save_scope(cpp_typecheck.cpp_scopes);
109+
cpp_typecheck.cpp_scopes.go_to(*scope);
110+
107111
cpp_typecheck.add_this_to_method_type(
108112
cpp_typecheck.lookup(scope->identifier),
109113
to_code_type(final_type),
110114
method_qualifier);
115+
}
111116

112117
get_final_identifier();
113118

src/cpp/cpp_typecheck.cpp

+6-9
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ void cpp_typecheckt::typecheck()
5454
for(auto &item : cpp_parse_tree.items)
5555
convert(item);
5656

57-
typecheck_method_bodies();
58-
5957
static_and_dynamic_initialization();
6058

59+
typecheck_method_bodies();
60+
6161
do_not_typechecked();
6262

6363
clean_up();
@@ -276,13 +276,10 @@ void cpp_typecheckt::clean_up()
276276

277277
const symbolt &symbol=cur_it->second;
278278

279-
// erase templates
280-
if(symbol.type.get_bool(ID_is_template) ||
281-
// Remove all symbols that have not been converted.
282-
// In particular this includes symbols created for functions
283-
// during template instantiation that are never called,
284-
// and hence, their bodies have not been converted.
285-
contains_cpp_name(symbol.value))
279+
// erase templates and all member functions that have not been converted
280+
if(
281+
symbol.type.get_bool(ID_is_template) ||
282+
deferred_typechecking.find(symbol.name) != deferred_typechecking.end())
286283
{
287284
symbol_table.erase(cur_it);
288285
continue;

src/cpp/cpp_typecheck.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ Author: Daniel Kroening, [email protected]
1212
#ifndef CPROVER_CPP_CPP_TYPECHECK_H
1313
#define CPROVER_CPP_CPP_TYPECHECK_H
1414

15-
#include <cassert>
16-
#include <set>
1715
#include <list>
1816
#include <map>
17+
#include <set>
18+
#include <unordered_set>
1919

2020
#include <util/std_code.h>
2121
#include <util/std_types.h>
@@ -257,7 +257,7 @@ class cpp_typecheckt:public c_typecheck_baset
257257

258258
void default_dtor(const symbolt &symb, cpp_declarationt &dtor);
259259

260-
codet dtor(const symbolt &symb);
260+
codet dtor(const symbolt &symb, const symbol_exprt &this_expr);
261261

262262
void check_member_initializers(
263263
const struct_typet::basest &bases,
@@ -588,6 +588,7 @@ class cpp_typecheckt:public c_typecheck_baset
588588
typedef std::list<irep_idt> dynamic_initializationst;
589589
dynamic_initializationst dynamic_initializations;
590590
bool disable_access_control; // Disable protect and private
591+
std::unordered_set<irep_idt> deferred_typechecking;
591592
};
592593

593594
#endif // CPROVER_CPP_CPP_TYPECHECK_H

src/cpp/cpp_typecheck_compound_type.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -1335,8 +1335,7 @@ void cpp_typecheckt::typecheck_member_function(
13351335
// Is this in a class template?
13361336
// If so, we defer typechecking until used.
13371337
if(cpp_scopes.current_scope().get_parent().is_template_scope())
1338-
{
1339-
}
1338+
deferred_typechecking.insert(new_symbol->name);
13401339
else // remember for later typechecking of body
13411340
add_method_body(new_symbol);
13421341
}
@@ -1360,9 +1359,11 @@ void cpp_typecheckt::add_this_to_method_type(
13601359
subtype.set(ID_C_volatile, true);
13611360

13621361
code_typet::parametert parameter(pointer_type(subtype));
1363-
parameter.set_identifier(ID_this); // check? Not qualified
1362+
parameter.set_identifier(ID_this);
13641363
parameter.set_base_name(ID_this);
13651364
parameter.set_this();
1365+
if(!cpp_scopes.current_scope().get_parent().is_template_scope())
1366+
convert_parameter(compound_symbol.mode, parameter);
13661367

13671368
code_typet::parameterst &parameters = type.parameters();
13681369
parameters.insert(parameters.begin(), parameter);

src/cpp/cpp_typecheck_conversions.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -576,15 +576,13 @@ bool cpp_typecheckt::standard_conversion_pointer_to_member(
576576
code_typet code1=to_code_type(expr.type().subtype());
577577
assert(!code1.parameters().empty());
578578
code_typet::parametert this1=code1.parameters()[0];
579-
INVARIANT(
580-
this1.get_base_name() == ID_this, "first parameter should be `this'");
579+
INVARIANT(this1.get_this(), "first parameter should be `this'");
581580
code1.parameters().erase(code1.parameters().begin());
582581

583582
code_typet code2=to_code_type(type.subtype());
584583
assert(!code2.parameters().empty());
585584
code_typet::parametert this2=code2.parameters()[0];
586-
INVARIANT(
587-
this2.get_base_name() == ID_this, "first parameter should be `this'");
585+
INVARIANT(this2.get_this(), "first parameter should be `this'");
588586
code2.parameters().erase(code2.parameters().begin());
589587

590588
if(this2.type().subtype().get_bool(ID_C_constant) &&

src/cpp/cpp_typecheck_destructor.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ void cpp_typecheckt::default_dtor(
4747
}
4848

4949
/// produces destructor code for a class object
50-
codet cpp_typecheckt::dtor(const symbolt &symbol)
50+
codet cpp_typecheckt::dtor(const symbolt &symbol, const symbol_exprt &this_expr)
5151
{
5252
assert(symbol.type.id()==ID_struct ||
5353
symbol.type.id()==ID_union);
@@ -85,7 +85,7 @@ codet cpp_typecheckt::dtor(const symbolt &symbol)
8585

8686
exprt ptrmember(ID_ptrmember);
8787
ptrmember.set(ID_component_name, c.get_name());
88-
ptrmember.operands().push_back(exprt("cpp-this"));
88+
ptrmember.operands().push_back(this_expr);
8989

9090
code_assignt assign(ptrmember, address);
9191
block.add(assign);
@@ -113,8 +113,7 @@ codet cpp_typecheckt::dtor(const symbolt &symbol)
113113

114114
exprt member(ID_ptrmember, type);
115115
member.set(ID_component_cpp_name, cppname);
116-
member.operands().push_back(
117-
symbol_exprt(ID_this, pointer_type(symbol.type)));
116+
member.operands().push_back(this_expr);
118117
member.add_source_location() = source_location;
119118

120119
const bool disabled_access_control = disable_access_control;
@@ -139,8 +138,7 @@ codet cpp_typecheckt::dtor(const symbolt &symbol)
139138
DATA_INVARIANT(bit->id() == ID_base, "base class expression expected");
140139
const symbolt &psymb = lookup(bit->type());
141140

142-
symbol_exprt this_ptr(ID_this, pointer_type(symbol.type));
143-
dereference_exprt object(this_ptr, psymb.type);
141+
dereference_exprt object{this_expr, psymb.type};
144142
object.add_source_location() = source_location;
145143

146144
const bool disabled_access_control = disable_access_control;

src/cpp/cpp_typecheck_expr.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ void cpp_typecheckt::typecheck_expr_address_of(exprt &expr)
698698
code_typet &code_type=to_code_type(op.type().subtype());
699699

700700
code_typet::parameterst &args=code_type.parameters();
701-
if(!args.empty() && args[0].get_base_name() == ID_this)
701+
if(!args.empty() && args.front().get_this())
702702
{
703703
// it's a pointer to member function
704704
const struct_tag_typet symbol(code_type.get(ID_C_member_name));
@@ -2192,7 +2192,7 @@ void cpp_typecheckt::typecheck_side_effect_function_call(
21922192
to_code_type(expr.function().type()).parameters();
21932193

21942194
if(
2195-
!parameters.empty() && parameters.front().get_base_name() == ID_this &&
2195+
!parameters.empty() && parameters.front().get_this() &&
21962196
!expr.arguments().empty())
21972197
{
21982198
const code_typet::parametert &parameter = parameters.front();

src/cpp/cpp_typecheck_fargs.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ bool cpp_typecheck_fargst::match(
9797

9898
// "this" is a special case -- we turn the pointer type
9999
// into a reference type to do the type matching
100-
if(it == ops.begin() && parameter.get_base_name() == ID_this)
100+
if(it == ops.begin() && parameter.get_this())
101101
{
102102
type.set(ID_C_reference, true);
103103
type.set(ID_C_this, true);

src/cpp/cpp_typecheck_function.cpp

+23-21
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ void cpp_typecheckt::convert_parameter(
3131
parameter.set_base_name(base_name);
3232
}
3333

34+
PRECONDITION(!cpp_scopes.current_scope().prefix.empty());
3435
irep_idt identifier=cpp_scopes.current_scope().prefix+
3536
id2string(base_name);
3637

@@ -90,22 +91,6 @@ void cpp_typecheckt::convert_function(symbolt &symbol)
9091
if(symbol.value.is_nil())
9192
return;
9293

93-
// if it is a destructor, add the implicit code
94-
if(to_code_type(symbol.type).return_type().id() == ID_destructor)
95-
{
96-
const symbolt &msymb=lookup(symbol.type.get(ID_C_member_name));
97-
98-
assert(symbol.value.id()==ID_code);
99-
assert(symbol.value.get(ID_statement)==ID_block);
100-
101-
if(
102-
!symbol.value.has_operands() || !symbol.value.op0().has_operands() ||
103-
symbol.value.op0().op0().id() != ID_already_typechecked)
104-
{
105-
symbol.value.copy_to_operands(dtor(msymb));
106-
}
107-
}
108-
10994
// enter appropriate scope
11095
cpp_save_scopet saved_scope(cpp_scopes);
11196
cpp_scopet &function_scope=cpp_scopes.set_scope(symbol.name);
@@ -123,13 +108,29 @@ void cpp_typecheckt::convert_function(symbolt &symbol)
123108
code_typet::parameterst &parameters=function_type.parameters();
124109
assert(parameters.size()>=1);
125110
code_typet::parametert &this_parameter_expr=parameters.front();
126-
function_scope.this_expr=exprt(ID_symbol, this_parameter_expr.type());
127-
function_scope.this_expr.set(
128-
ID_identifier, this_parameter_expr.get_identifier());
111+
function_scope.this_expr = symbol_exprt{
112+
this_parameter_expr.get_identifier(), this_parameter_expr.type()};
129113
}
130114
else
131115
function_scope.this_expr.make_nil();
132116

117+
// if it is a destructor, add the implicit code
118+
if(to_code_type(symbol.type).return_type().id() == ID_destructor)
119+
{
120+
const symbolt &msymb = lookup(symbol.type.get(ID_C_member_name));
121+
122+
PRECONDITION(symbol.value.id() == ID_code);
123+
PRECONDITION(symbol.value.get(ID_statement) == ID_block);
124+
125+
if(
126+
!symbol.value.has_operands() || !symbol.value.op0().has_operands() ||
127+
symbol.value.op0().op0().id() != ID_already_typechecked)
128+
{
129+
symbol.value.copy_to_operands(
130+
dtor(msymb, to_symbol_expr(function_scope.this_expr)));
131+
}
132+
}
133+
133134
// do the function body
134135
start_typecheck_code();
135136

@@ -147,6 +148,8 @@ void cpp_typecheckt::convert_function(symbolt &symbol)
147148
symbol.value.type()=symbol.type;
148149

149150
return_type = old_return_type;
151+
152+
deferred_typechecking.erase(symbol.name);
150153
}
151154

152155
/// for function overloading
@@ -171,8 +174,7 @@ irep_idt cpp_typecheckt::function_identifier(const typet &type)
171174
code_typet::parameterst::const_iterator it=
172175
parameters.begin();
173176

174-
if(it!=parameters.end() &&
175-
it->get_identifier()==ID_this)
177+
if(it != parameters.end() && it->get_this())
176178
{
177179
const typet &pointer=it->type();
178180
const typet &symbol =pointer.subtype();

src/cpp/cpp_typecheck_initializer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void cpp_typecheckt::convert_initializer(symbolt &symbol)
9494
exprt new_object(ID_new_object, parameter.type());
9595
new_object.set(ID_C_lvalue, true);
9696

97-
if(parameter.get_base_name() == ID_this)
97+
if(parameter.get_this())
9898
{
9999
fargs.has_object = true;
100100
new_object.type() = parameter.type().subtype();

src/cpp/cpp_typecheck_resolve.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -2075,7 +2075,7 @@ void cpp_typecheck_resolvet::apply_template_args(
20752075

20762076
if(
20772077
!code_type.parameters().empty() &&
2078-
code_type.parameters()[0].get_base_name() == ID_this)
2078+
code_type.parameters().front().get_this())
20792079
{
20802080
// do we have an object?
20812081
if(fargs.has_object)
@@ -2129,9 +2129,7 @@ bool cpp_typecheck_resolvet::disambiguate_functions(
21292129
const code_typet::parameterst &parameters=type.parameters();
21302130
const code_typet::parametert &parameter=parameters.front();
21312131

2132-
INVARIANT(
2133-
parameter.get_base_name() == ID_this,
2134-
"first parameter should be `this'");
2132+
INVARIANT(parameter.get_this(), "first parameter should be `this'");
21352133

21362134
if(type.return_type().id() == ID_constructor)
21372135
{

src/cpp/cpp_typecheck_type.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,12 @@ void cpp_typecheckt::typecheck_type(typet &type)
106106
code_typet::parameterst &parameters =
107107
to_code_type(type.subtype()).parameters();
108108

109-
if(parameters.empty() || parameters.front().get_base_name() != ID_this)
109+
if(parameters.empty() || !parameters.front().get_this())
110110
{
111111
// Add 'this' to the parameters
112112
code_typet::parametert a0(pointer_type(class_object));
113113
a0.set_base_name(ID_this);
114+
a0.set_this();
114115
parameters.insert(parameters.begin(), a0);
115116
}
116117
}

0 commit comments

Comments
 (0)