Skip to content

Commit 3fd321c

Browse files
smowtonthk123
authored andcommitted
Remove virtual functions: cast argument types as necessary
For example, when List<E> extends the Collection<E> interface, its overrides of methods accepting an element, such as add(E), are given in terms of its own E, not that of Collection. Therefore we must cast from Collection::E* to List::E* when using that particular override. Only typecast if the parameter types are distinct
1 parent 0a3b99b commit 3fd321c

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed

src/goto-programs/remove_virtual_functions.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,35 @@ static void create_static_function_call(
113113
const namespacet &ns)
114114
{
115115
call.function() = function_symbol;
116-
// Cast the `this` pointer to the correct type for the new callee:
117-
const auto &callee_type =
118-
to_code_type(ns.lookup(function_symbol.get_identifier()).type);
119-
const code_typet::parametert *this_param = callee_type.get_this();
116+
// Cast the pointers to the correct type for the new callee:
117+
// Note the `this` pointer is expected to change type, but other pointers
118+
// could also change due to e.g. using a different alias to refer to the same
119+
// type (in Java, for example, we see ArrayList.add(ArrayList::E arg)
120+
// overriding Collection.add(Collection::E arg))
121+
const auto &callee_parameters =
122+
to_code_type(ns.lookup(function_symbol.get_identifier()).type).parameters();
123+
auto &call_args = call.arguments();
124+
120125
INVARIANT(
121-
this_param != nullptr,
122-
"Virtual function callees must have a `this` argument");
123-
typet need_type = this_param->type();
124-
if(!type_eq(call.arguments()[0].type(), need_type, ns))
125-
call.arguments()[0].make_typecast(need_type);
126+
callee_parameters.size() == call_args.size(),
127+
"function overrides must have matching argument counts");
128+
129+
for(std::size_t i = 0; i < call_args.size(); ++i)
130+
{
131+
const typet &need_type = callee_parameters[i].type();
132+
133+
if(!type_eq(call_args[i].type(), need_type, ns))
134+
{
135+
// If this wasn't language agnostic code we'd also like to check
136+
// compatibility-- for example, Java overrides may have differing generic
137+
// qualifiers, but not different base types.
138+
INVARIANT(
139+
call_args[i].type().id() == ID_pointer,
140+
"where overriding function argument types differ, "
141+
"those arguments must be pointer-typed");
142+
call_args[i].make_typecast(need_type);
143+
}
144+
}
126145
}
127146

128147
/// Replace virtual function call with a static function call

0 commit comments

Comments
 (0)