7
7
\*******************************************************************/
8
8
9
9
#include < util/prefix.h>
10
+ #include < util/type_eq.h>
10
11
11
12
#include " class_hierarchy.h"
12
13
#include " remove_virtual_functions.h"
@@ -43,13 +44,23 @@ class remove_virtual_functionst
43
44
class functiont
44
45
{
45
46
public:
47
+ functiont () {}
48
+ explicit functiont (const irep_idt& _class_id) :
49
+ class_id(_class_id)
50
+ {}
51
+
46
52
symbol_exprt symbol_expr;
47
53
irep_idt class_id;
48
54
};
49
55
50
56
typedef std::vector<functiont> functionst;
51
57
void get_functions (const exprt &, functionst &);
52
- exprt get_method (const irep_idt &class_id, const irep_idt &component_name);
58
+ void get_child_functions_rec (
59
+ const irep_idt &, const symbol_exprt &,
60
+ const irep_idt &, functionst &) const ;
61
+ exprt get_method (
62
+ const irep_idt &class_id,
63
+ const irep_idt &component_name) const ;
53
64
54
65
exprt build_class_identifier (const exprt &);
55
66
};
@@ -170,33 +181,60 @@ void remove_virtual_functionst::remove_virtual_function(
170
181
goto_programt new_code_calls;
171
182
goto_programt new_code_gotos;
172
183
184
+ // Get a pointer from which we can extract a clsid.
185
+ // If it's already a pointer to an object of some sort, just use it;
186
+ // if it's void* then use the parent of all possible candidates,
187
+ // which by the nature of get_functions happens to be the last candidate.
188
+
189
+ exprt this_expr=code.arguments ()[0 ];
190
+ assert (this_expr.type ().id ()==ID_pointer &&
191
+ " Non-pointer this-arg in remove-virtuals?" );
192
+ const auto &points_to=this_expr.type ().subtype ();
193
+ if (points_to==empty_typet ())
194
+ {
195
+ symbol_typet symbol_type (functions.back ().class_id );
196
+ this_expr=typecast_exprt (this_expr, pointer_typet (symbol_type));
197
+ }
198
+ exprt deref=dereference_exprt (this_expr, this_expr.type ().subtype ());
199
+ exprt c_id2=build_class_identifier (deref);
200
+
201
+ goto_programt::targett last_function;
173
202
for (const auto &fun : functions)
174
203
{
175
- // call function
176
204
goto_programt::targett t1=new_code_calls.add_instruction ();
177
- t1->make_function_call (code);
178
- to_code_function_call (t1->code ).function ()=fun.symbol_expr ;
205
+ if (!fun.symbol_expr .get_identifier ().empty ())
206
+ {
207
+ // call function
208
+ t1->make_function_call (code);
209
+ auto &newcall=to_code_function_call (t1->code );
210
+ newcall.function ()=fun.symbol_expr ;
211
+ pointer_typet need_type (symbol_typet (fun.symbol_expr .get (ID_C_class)));
212
+ if (!type_eq (newcall.arguments ()[0 ].type (), need_type, ns))
213
+ newcall.arguments ()[0 ].make_typecast (need_type);
214
+ }
215
+ else
216
+ {
217
+ // No definition for this type; shouldn't be possible...
218
+ t1->make_assertion (false_exprt ());
219
+ }
220
+
221
+ last_function=t1;
179
222
180
223
// goto final
181
224
goto_programt::targett t3=new_code_calls.add_instruction ();
182
225
t3->make_goto (t_final, true_exprt ());
183
226
184
- exprt this_expr=code.arguments ()[0 ];
185
- if (this_expr.type ().id ()!=ID_pointer ||
186
- this_expr.type ().id ()!=ID_struct)
187
- {
188
- symbol_typet symbol_type (fun.class_id );
189
- this_expr=typecast_exprt (this_expr, pointer_typet (symbol_type));
190
- }
191
-
192
- exprt deref=dereference_exprt (this_expr, this_expr.type ().subtype ());
193
227
exprt c_id1=constant_exprt (fun.class_id , string_typet ());
194
- exprt c_id2=build_class_identifier (deref);
195
228
196
229
goto_programt::targett t4=new_code_gotos.add_instruction ();
197
230
t4->make_goto (t1, equal_exprt (c_id1, c_id2));
198
231
}
199
232
233
+ // In any other case (most likely a stub class) call the most basic
234
+ // version of the method we know to exist:
235
+ goto_programt::targett fallthrough=new_code_gotos.add_instruction ();
236
+ fallthrough->make_goto (last_function);
237
+
200
238
goto_programt new_code;
201
239
202
240
// patch them all together
@@ -226,6 +264,61 @@ void remove_virtual_functionst::remove_virtual_function(
226
264
227
265
/* ******************************************************************\
228
266
267
+ Function: remove_virtual_functionst::get_child_functions_rec
268
+
269
+ Inputs: `this_id`: class name
270
+ `last_method_defn`: the most-derived parent of `this_id`
271
+ to define the requested function
272
+ `component_name`: name of the function searched for
273
+
274
+ Outputs: `functions` is assigned a list of {class name, function symbol}
275
+ pairs indicating that if `this` is of the given class, then the
276
+ call will target the given function. Thus if A <: B <: C and A
277
+ and C provide overrides of `f` (but B does not),
278
+ get_child_functions_rec("C", C.f, "f") -> [{"C", C.f},
279
+ {"B", C.f},
280
+ {"A", A.f}]
281
+
282
+ Purpose: Used by get_functions to track the most-derived parent that
283
+ provides an override of a given function.
284
+
285
+ \*******************************************************************/
286
+
287
+ void remove_virtual_functionst::get_child_functions_rec (
288
+ const irep_idt &this_id,
289
+ const symbol_exprt &last_method_defn,
290
+ const irep_idt &component_name,
291
+ functionst &functions) const
292
+ {
293
+ auto findit=class_hierarchy.class_map .find (this_id);
294
+ if (findit==class_hierarchy.class_map .end ())
295
+ return ;
296
+
297
+ for (const auto & child : findit->second .children )
298
+ {
299
+ exprt method=get_method (child, component_name);
300
+ functiont function (child);
301
+ if (method.is_not_nil ())
302
+ {
303
+ function.symbol_expr =to_symbol_expr (method);
304
+ function.symbol_expr .set (ID_C_class, child);
305
+ }
306
+ else
307
+ {
308
+ function.symbol_expr =last_method_defn;
309
+ }
310
+ functions.push_back (function);
311
+
312
+ get_child_functions_rec (
313
+ child,
314
+ function.symbol_expr ,
315
+ component_name,
316
+ functions);
317
+ }
318
+ }
319
+
320
+ /* ******************************************************************\
321
+
229
322
Function: remove_virtual_functionst::get_functions
230
323
231
324
Inputs:
@@ -243,23 +336,7 @@ void remove_virtual_functionst::get_functions(
243
336
const irep_idt class_id=function.get (ID_C_class);
244
337
const irep_idt component_name=function.get (ID_component_name);
245
338
assert (!class_id.empty ());
246
-
247
- // iterate over all children, transitively
248
- std::vector<irep_idt> children=
249
- class_hierarchy.get_children_trans (class_id);
250
-
251
- for (const auto &child : children)
252
- {
253
- exprt method=get_method (child, component_name);
254
- if (method.is_not_nil ())
255
- {
256
- functiont function;
257
- function.class_id =child;
258
- function.symbol_expr =to_symbol_expr (method);
259
- function.symbol_expr .set (ID_C_class, child);
260
- functions.push_back (function);
261
- }
262
- }
339
+ functiont root_function;
263
340
264
341
// Start from current class, go to parents until something
265
342
// is found.
@@ -269,11 +346,9 @@ void remove_virtual_functionst::get_functions(
269
346
exprt method=get_method (c, component_name);
270
347
if (method.is_not_nil ())
271
348
{
272
- functiont function;
273
- function.class_id =c;
274
- function.symbol_expr =to_symbol_expr (method);
275
- function.symbol_expr .set (ID_C_class, c);
276
- functions.push_back (function);
349
+ root_function.class_id =c;
350
+ root_function.symbol_expr =to_symbol_expr (method);
351
+ root_function.symbol_expr .set (ID_C_class, c);
277
352
break ; // abort
278
353
}
279
354
@@ -283,6 +358,21 @@ void remove_virtual_functionst::get_functions(
283
358
if (parents.empty ()) break ;
284
359
c=parents.front ();
285
360
}
361
+
362
+ if (root_function.class_id .empty ())
363
+ {
364
+ // No definition here; this is an abstract function.
365
+ root_function.class_id =class_id;
366
+ }
367
+
368
+ // iterate over all children, transitively
369
+ get_child_functions_rec (
370
+ class_id,
371
+ root_function.symbol_expr ,
372
+ component_name,
373
+ functions);
374
+
375
+ functions.push_back (root_function);
286
376
}
287
377
288
378
/* ******************************************************************\
@@ -299,7 +389,7 @@ Function: remove_virtual_functionst::get_method
299
389
300
390
exprt remove_virtual_functionst::get_method (
301
391
const irep_idt &class_id,
302
- const irep_idt &component_name)
392
+ const irep_idt &component_name) const
303
393
{
304
394
irep_idt id=id2string (class_id)+" ." +
305
395
id2string (component_name);
0 commit comments