@@ -30,6 +30,12 @@ class remove_virtual_functionst
3030
3131 bool remove_virtual_functions (goto_programt &goto_program);
3232
33+ void remove_virtual_function (
34+ goto_programt &goto_program,
35+ goto_programt::targett target,
36+ const dispatch_table_entriest &functions,
37+ virtual_dispatch_fallback_actiont fallback_action);
38+
3339protected:
3440 const namespacet ns;
3541 const symbol_tablet &symbol_table;
@@ -40,25 +46,12 @@ class remove_virtual_functionst
4046 goto_programt &goto_program,
4147 goto_programt::targett target);
4248
43- class functiont
44- {
45- public:
46- functiont () {}
47- explicit functiont (const irep_idt &_class_id) :
48- class_id(_class_id)
49- {}
50-
51- symbol_exprt symbol_expr;
52- irep_idt class_id;
53- };
54-
55- typedef std::vector<functiont> functionst;
56- void get_functions (const exprt &, functionst &);
49+ void get_functions (const exprt &, dispatch_table_entriest &);
5750 void get_child_functions_rec (
5851 const irep_idt &,
5952 const symbol_exprt &,
6053 const irep_idt &,
61- functionst &,
54+ dispatch_table_entriest &,
6255 std::set<irep_idt> &visited) const ;
6356 exprt get_method (
6457 const irep_idt &class_id,
@@ -81,25 +74,46 @@ void remove_virtual_functionst::remove_virtual_function(
8174 const code_function_callt &code=
8275 to_code_function_call (target->code );
8376
84- const auto &vcall_source_loc=target->source_location ;
85-
8677 const exprt &function=code.function ();
87- assert (function.id ()==ID_virtual_function);
88- assert (!code.arguments ().empty ());
89-
90- functionst functions;
78+ INVARIANT (
79+ function.id ()==ID_virtual_function,
80+ " remove_virtual_function must take a virtual function call instruction" );
81+ INVARIANT (
82+ !code.arguments ().empty (),
83+ " virtual function calls must have at least a this-argument" );
84+
85+ dispatch_table_entriest functions;
9186 get_functions (function, functions);
9287
88+ remove_virtual_function (
89+ goto_program,
90+ target,
91+ functions,
92+ virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION);
93+ }
94+
95+ void remove_virtual_functionst::remove_virtual_function (
96+ goto_programt &goto_program,
97+ goto_programt::targett target,
98+ const dispatch_table_entriest &functions,
99+ virtual_dispatch_fallback_actiont fallback_action)
100+ {
101+ INVARIANT (
102+ target->is_function_call (),
103+ " remove_virtual_function must target a FUNCTION_CALL instruction" );
104+ const code_function_callt &code=
105+ to_code_function_call (target->code );
106+
93107 if (functions.empty ())
94108 {
95109 target->make_skip ();
96110 return ; // give up
97111 }
98112
99113 // only one option?
100- if (functions.size ()==1 )
114+ if (functions.size ()==1 &&
115+ fallback_action==virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION)
101116 {
102- assert (target->is_function_call ());
103117 if (functions.begin ()->symbol_expr ==symbol_exprt ())
104118 target->make_skip ();
105119 else
@@ -108,6 +122,8 @@ void remove_virtual_functionst::remove_virtual_function(
108122 return ;
109123 }
110124
125+ const auto &vcall_source_loc=target->source_location ;
126+
111127 // the final target is a skip
112128 goto_programt final_skip;
113129
@@ -122,16 +138,29 @@ void remove_virtual_functionst::remove_virtual_function(
122138 goto_programt new_code_gotos;
123139
124140 exprt this_expr=code.arguments ()[0 ];
125- // If necessary, cast to the last candidate function to
126- // get the object's clsid. By the structure of get_functions,
127- // this is the parent of all other classes under consideration.
128- const auto &base_classid=functions.back ().class_id ;
129- const auto &base_function_symbol=functions.back ().symbol_expr ;
130- symbol_typet suggested_type (base_classid);
131- exprt c_id2=get_class_identifier_field (this_expr, suggested_type, ns);
141+ const auto &last_function_symbol=functions.back ().symbol_expr ;
142+
143+ const typet &this_type=this_expr.type ();
144+ INVARIANT (this_type.id () == ID_pointer, " this parameter must be a pointer" );
145+ INVARIANT (
146+ this_type.subtype () != empty_typet (),
147+ " this parameter must not be a void pointer" );
148+
149+ // So long as `this` is already not `void*` typed, the second parameter
150+ // is ignored:
151+ exprt c_id2=get_class_identifier_field (this_expr, symbol_typet (), ns);
152+
153+ // If instructed, add an ASSUME(FALSE) to handle the case where we don't
154+ // match any expected type:
155+ if (fallback_action==virtual_dispatch_fallback_actiont::ASSUME_FALSE)
156+ {
157+ auto newinst=new_code_calls.add_instruction (ASSUME);
158+ newinst->guard =false_exprt ();
159+ newinst->source_location =vcall_source_loc;
160+ }
132161
133162 std::map<irep_idt, goto_programt::targett> calls;
134- // Note backwards iteration, to get the least-derived candidate first.
163+ // Note backwards iteration, to get the fallback candidate first.
135164 for (auto it=functions.crbegin (), itend=functions.crend (); it!=itend; ++it)
136165 {
137166 const auto &fun=*it;
@@ -149,8 +178,13 @@ void remove_virtual_functionst::remove_virtual_function(
149178 t1->make_function_call (code);
150179 auto &newcall=to_code_function_call (t1->code );
151180 newcall.function ()=fun.symbol_expr ;
152- typet need_type=
153- pointer_type (symbol_typet (fun.symbol_expr .get (ID_C_class)));
181+ // Cast the `this` pointer to the correct type for the new callee:
182+ const auto &callee_type=
183+ to_code_type (ns.lookup (fun.symbol_expr .get_identifier ()).type );
184+ INVARIANT (
185+ callee_type.has_this (),
186+ " Virtual function callees must have a `this` argument" );
187+ typet need_type=callee_type.parameters ()[0 ].type ();
154188 if (!type_eq (newcall.arguments ()[0 ].type (), need_type, ns))
155189 newcall.arguments ()[0 ].make_typecast (need_type);
156190 }
@@ -166,9 +200,10 @@ void remove_virtual_functionst::remove_virtual_function(
166200 t3->make_goto (t_final, true_exprt ());
167201 }
168202
169- // If this calls the base function we just fall through.
203+ // If this calls the fallback function we just fall through.
170204 // Otherwise branch to the right call:
171- if (fun.symbol_expr !=base_function_symbol)
205+ if (fallback_action!=virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION ||
206+ fun.symbol_expr !=last_function_symbol)
172207 {
173208 exprt c_id1=constant_exprt (fun.class_id , string_typet ());
174209 goto_programt::targett t4=new_code_gotos.add_instruction ();
@@ -221,7 +256,7 @@ void remove_virtual_functionst::get_child_functions_rec(
221256 const irep_idt &this_id,
222257 const symbol_exprt &last_method_defn,
223258 const irep_idt &component_name,
224- functionst &functions,
259+ dispatch_table_entriest &functions,
225260 std::set<irep_idt> &visited) const
226261{
227262 auto findit=class_hierarchy.class_map .find (this_id);
@@ -233,7 +268,7 @@ void remove_virtual_functionst::get_child_functions_rec(
233268 if (!visited.insert (child).second )
234269 continue ;
235270 exprt method=get_method (child, component_name);
236- functiont function (child);
271+ dispatch_table_entryt function (child);
237272 if (method.is_not_nil ())
238273 {
239274 function.symbol_expr =to_symbol_expr (method);
@@ -256,7 +291,7 @@ void remove_virtual_functionst::get_child_functions_rec(
256291
257292void remove_virtual_functionst::get_functions (
258293 const exprt &function,
259- functionst &functions)
294+ dispatch_table_entriest &functions)
260295{
261296 const irep_idt class_id=function.get (ID_C_class);
262297 const irep_idt component_name=function.get (ID_component_name);
@@ -266,7 +301,7 @@ void remove_virtual_functionst::get_functions(
266301 symbol_table, class_hierarchy);
267302 const resolve_concrete_function_callt::concrete_function_callt &
268303 resolved_call=get_virtual_call_target (class_id, component_name);
269- functiont root_function;
304+ dispatch_table_entryt root_function;
270305
271306 if (resolved_call.is_valid ())
272307 {
@@ -373,3 +408,17 @@ void remove_virtual_functions(goto_modelt &goto_model)
373408 remove_virtual_functions (
374409 goto_model.symbol_table , goto_model.goto_functions );
375410}
411+
412+ void remove_virtual_function (
413+ goto_modelt &goto_model,
414+ goto_programt &goto_program,
415+ goto_programt::targett instruction,
416+ const dispatch_table_entriest &dispatch_table,
417+ virtual_dispatch_fallback_actiont fallback_action)
418+ {
419+ remove_virtual_functionst
420+ rvf (goto_model.symbol_table , goto_model.goto_functions );
421+
422+ rvf.remove_virtual_function (
423+ goto_program, instruction, dispatch_table, fallback_action);
424+ }
0 commit comments