On 7/24/26 6:48 PM, Odysseas Georgoudis wrote:
This patch adjusts successful scalar virtual-call results to the static
call type after caching the underlying function result. The cache
therefore retains the final overrider's declared result type for direct
calls.
+ /* A virtual call with a covariant return type can evaluate the final
+ overrider directly, whose result has its declared type rather than
+ the static type of the call. Adjust after caching so a direct call
+ can reuse the result with its original type. */
+ if (!*non_constant_p
+ && !*overflow_p
+ && !*jump_target
+ && DECL_VIRTUAL_P (fun)
+ && result != void_node
+ && scalarish_type_p (TREE_TYPE (t))
+ && !same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (result), TREE_TYPE (t)))
+ result = adjust_temp_type (TREE_TYPE (t), result);
What if the base is at a non-zero offset from the derived type?
If I change your testcase to add another base, i.e.
struct B
{
virtual constexpr B *clone(bool null)
{
return null ? nullptr : this;
}
};
struct C
{
virtual void dummy () { }
};
struct D : C, B
{
constexpr D *clone(bool null) override
{
return null ? nullptr : this;
}
};
then we still hit the same ICE.
Jason