@@ -476,11 +476,34 @@ csvsa_function_contextt::get_virtual_callees(locationt l_call) const
476
476
exprt val;
477
477
if (raw_value.id () == ID_unknown)
478
478
{
479
- INVARIANT (
480
- raw_value.type ().id () == ID_pointer,
481
- " an unknown expression used as a `this` arg should have pointer type" );
479
+ // Under some circumstances the ID_unknown can indicate the type of the
480
+ // referred object, not the pointer. Given there are no hard and fast
481
+ // rules for the type of the returned ID_unknown we really just try our
482
+ // best to get a good hint about the referred object type here.
483
+
484
+ typet unknown_type = raw_value.type ();
485
+ if (unknown_type.id () == ID_pointer)
486
+ unknown_type = unknown_type.subtype ();
487
+
488
+ unknown_type = ns.follow (unknown_type);
489
+
490
+ if (unknown_type.id () != ID_struct)
491
+ {
492
+ // Last fallback: suppose the `this` argument type matches the virtual
493
+ // callee type. For example, if we're calling A.f() and `this` appears
494
+ // to be an unknown integer or something else impossible to call,
495
+ // we'll guess it must be at least an A*.
496
+ const code_typet::parametert *this_parameter =
497
+ to_code_type (call.function ().type ()).get_this ();
498
+ INVARIANT (
499
+ this_parameter != nullptr ,
500
+ " Virtual call should have 'this' parameter" );
501
+
502
+ unknown_type =
503
+ ns.follow (to_pointer_type (this_parameter->type ()).subtype ());
504
+ }
482
505
483
- val = exprt (ID_unknown, raw_value. type (). subtype () );
506
+ val = exprt (ID_unknown, unknown_type );
484
507
485
508
// If the unknown is a parent of the expected this-argument type, or is of
486
509
// opaque type and so unknown position in the class hierarchy, lift
0 commit comments